mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-28 14:17:17 +00:00
231 lines
6.3 KiB
Go
231 lines
6.3 KiB
Go
package depositcontract
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"log"
|
|
"math/big"
|
|
"testing"
|
|
|
|
ethereum "github.com/ethereum/go-ethereum"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
|
)
|
|
|
|
var (
|
|
amount33Eth, _ = new(big.Int).SetString("33000000000000000000", 10)
|
|
amount32Eth, _ = new(big.Int).SetString("32000000000000000000", 10)
|
|
amountLessThan1Eth, _ = new(big.Int).SetString("500000000000000000", 10)
|
|
)
|
|
|
|
type testAccount struct {
|
|
addr common.Address
|
|
contract *DepositContract
|
|
contractAddr common.Address
|
|
backend *backends.SimulatedBackend
|
|
txOpts *bind.TransactOpts
|
|
}
|
|
|
|
func setup() (*testAccount, error) {
|
|
genesis := make(core.GenesisAlloc)
|
|
privKey, _ := crypto.GenerateKey()
|
|
pubKeyECDSA, ok := privKey.Public().(*ecdsa.PublicKey)
|
|
if !ok {
|
|
return nil, fmt.Errorf("error casting public key to ECDSA")
|
|
}
|
|
|
|
// strip off the 0x and the first 2 characters 04 which is always the EC prefix and is not required.
|
|
publicKeyBytes := crypto.FromECDSAPub(pubKeyECDSA)[4:]
|
|
var pubKey = make([]byte, 48)
|
|
copy(pubKey[:], []byte(publicKeyBytes))
|
|
|
|
addr := crypto.PubkeyToAddress(privKey.PublicKey)
|
|
txOpts := bind.NewKeyedTransactor(privKey)
|
|
startingBalance, _ := new(big.Int).SetString("100000000000000000000000000000000000000", 10)
|
|
genesis[addr] = core.GenesisAccount{Balance: startingBalance}
|
|
backend := backends.NewSimulatedBackend(genesis, 210000000000)
|
|
|
|
depositsRequired := big.NewInt(8)
|
|
minDeposit := big.NewInt(1e9)
|
|
maxDeposit := big.NewInt(32e9)
|
|
contractAddr, _, contract, err := DeployDepositContract(txOpts, backend, depositsRequired, minDeposit, maxDeposit, big.NewInt(1), addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &testAccount{addr, contract, contractAddr, backend, txOpts}, nil
|
|
}
|
|
|
|
func TestSetupRegistrationContract_OK(t *testing.T) {
|
|
_, err := setup()
|
|
if err != nil {
|
|
log.Fatalf("Can not deploy validator registration contract: %v", err)
|
|
}
|
|
}
|
|
|
|
// negative test case, deposit with less than 1 ETH which is less than the top off amount.
|
|
func TestRegister_Below1ETH(t *testing.T) {
|
|
testAccount, err := setup()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
testAccount.txOpts.Value = amountLessThan1Eth
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{})
|
|
if err == nil {
|
|
t.Error("Validator registration should have failed with insufficient deposit")
|
|
}
|
|
}
|
|
|
|
// negative test case, deposit with more than 32 ETH which is more than the asked amount.
|
|
func TestRegister_Above32Eth(t *testing.T) {
|
|
testAccount, err := setup()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
testAccount.txOpts.Value = amount33Eth
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{})
|
|
if err == nil {
|
|
t.Error("Validator registration should have failed with more than asked deposit amount")
|
|
}
|
|
}
|
|
|
|
// normal test case, test depositing 32 ETH and verify HashChainValue event is correctly emitted.
|
|
func TestValidatorRegister_OK(t *testing.T) {
|
|
testAccount, err := setup()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testAccount.txOpts.Value = amount32Eth
|
|
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'A'})
|
|
testAccount.backend.Commit()
|
|
if err != nil {
|
|
t.Errorf("Validator registration failed: %v", err)
|
|
}
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'B'})
|
|
testAccount.backend.Commit()
|
|
if err != nil {
|
|
t.Errorf("Validator registration failed: %v", err)
|
|
}
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'C'})
|
|
testAccount.backend.Commit()
|
|
if err != nil {
|
|
t.Errorf("Validator registration failed: %v", err)
|
|
}
|
|
|
|
query := ethereum.FilterQuery{
|
|
Addresses: []common.Address{
|
|
testAccount.contractAddr,
|
|
},
|
|
}
|
|
|
|
logs, err := testAccount.backend.FilterLogs(context.Background(), query)
|
|
if err != nil {
|
|
t.Fatalf("Unable to get logs of deposit contract: %v", err)
|
|
}
|
|
|
|
merkleTreeIndex := make([]uint64, 5)
|
|
depositData := make([][]byte, 5)
|
|
|
|
for i, log := range logs {
|
|
_, data, idx, _, err := UnpackDepositLogData(log.Data)
|
|
if err != nil {
|
|
t.Fatalf("Unable to unpack log data: %v", err)
|
|
}
|
|
merkleTreeIndex[i] = binary.LittleEndian.Uint64(idx)
|
|
depositData[i] = data
|
|
}
|
|
|
|
if merkleTreeIndex[0] != 0 {
|
|
t.Errorf("Deposit event total desposit count miss matched. Want: %d, Got: %d", 1, merkleTreeIndex[0])
|
|
}
|
|
|
|
if merkleTreeIndex[1] != 1 {
|
|
t.Errorf("Deposit event total desposit count miss matched. Want: %d, Got: %d", 2, merkleTreeIndex[1])
|
|
}
|
|
|
|
if merkleTreeIndex[2] != 2 {
|
|
t.Errorf("Deposit event total desposit count miss matched. Want: %v, Got: %v", 3, merkleTreeIndex[2])
|
|
}
|
|
}
|
|
|
|
// normal test case, test beacon chain start log event.
|
|
func TestChainStart_OK(t *testing.T) {
|
|
testAccount, err := setup()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testAccount.txOpts.Value = amount32Eth
|
|
|
|
for i := 0; i < 8; i++ {
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'A'})
|
|
if err != nil {
|
|
t.Errorf("Validator registration failed: %v", err)
|
|
}
|
|
}
|
|
|
|
testAccount.backend.Commit()
|
|
|
|
query := ethereum.FilterQuery{
|
|
Addresses: []common.Address{
|
|
testAccount.contractAddr,
|
|
},
|
|
}
|
|
|
|
logs, err := testAccount.backend.FilterLogs(context.Background(), query)
|
|
if err != nil {
|
|
t.Fatalf("Unable to get logs %v", err)
|
|
}
|
|
|
|
if logs[8].Topics[0] != hashutil.Hash([]byte("ChainStart(bytes32,bytes)")) {
|
|
t.Error("Chain start even did not get emitted")
|
|
}
|
|
}
|
|
|
|
func TestDrain(t *testing.T) {
|
|
testAccount, err := setup()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testAccount.txOpts.Value = amount32Eth
|
|
|
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'A'})
|
|
if err != nil {
|
|
t.Errorf("Validator registration failed: %v", err)
|
|
}
|
|
|
|
testAccount.backend.Commit()
|
|
|
|
ctx := context.Background()
|
|
bal, err := testAccount.backend.BalanceAt(ctx, testAccount.contractAddr, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bal.Cmp(amount32Eth) != 0 {
|
|
t.Fatal("deposit didnt work")
|
|
}
|
|
|
|
testAccount.txOpts.Value = big.NewInt(0)
|
|
if _, err := testAccount.contract.Drain(testAccount.txOpts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
testAccount.backend.Commit()
|
|
|
|
bal, err = testAccount.backend.BalanceAt(ctx, testAccount.contractAddr, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if big.NewInt(0).Cmp(bal) != 0 {
|
|
t.Errorf("Drain did not drain balance: %v", bal)
|
|
}
|
|
}
|