mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-03 00:27:38 +00:00
Update Registration Contract in Solidity (#996)
This commit is contained in:
parent
c5d4c27989
commit
b8041e3dca
@ -8,6 +8,8 @@
|
|||||||
"error",
|
"error",
|
||||||
"double"
|
"double"
|
||||||
],
|
],
|
||||||
|
"security/no-inline-assembly": ["warning"],
|
||||||
|
|
||||||
"indentation": [
|
"indentation": [
|
||||||
"error",
|
"error",
|
||||||
4
|
4
|
||||||
|
@ -1,10 +1,23 @@
|
|||||||
## Validator Registration Contract
|
## Validator Registration Contract
|
||||||
|
|
||||||
For beacon chain design, a validator will deposit 32 ETH to the main chain smart contract.
|
A validator will deposit 32 ETH to the registration
|
||||||
|
contract. The contract will generate a receipt showing the validator as a
|
||||||
|
qualified validator.
|
||||||
The deposit is considered to be burned. As you burn the 32 ETH to participate,
|
The deposit is considered to be burned. As you burn the 32 ETH to participate,
|
||||||
the beacon chain will see it and will credit the validator with the validator bond,
|
the beacon chain will see it and will credit the validator with the validator bond,
|
||||||
and the validator can begin to validate. At some point in the future, after a hard fork,
|
At some point in the future, after a hard fork,
|
||||||
the original deposit + interest can be withdrawn back on one of the shards.
|
the original deposit + interest can be withdrawn back on one of the shards.
|
||||||
|
To call the `registration` function, it takes arguments of `pubkey`,
|
||||||
|
`proof_of_possession`, `withdrawal_credentials` and `randao_commitment`.
|
||||||
|
If the user wants to deposit more than `DEPOSIT_SIZE` ETH, they would
|
||||||
|
need to make multiple `registration` calls.
|
||||||
|
When the contract publishes the `ChainStart` log, beacon nodes will
|
||||||
|
start off the beacon chain with slot 0 and last recorded `block.timestamp`
|
||||||
|
as beacon chain genesis time.
|
||||||
|
The registration contract generate receipts with the various arguments
|
||||||
|
for consumption by beacon nodes. It does not validate `proof_of_possession`
|
||||||
|
and `withdrawal_credentials`, pushing the validation logic to the
|
||||||
|
beacon chain.
|
||||||
|
|
||||||
## How to execute tests
|
## How to execute tests
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,48 +1,111 @@
|
|||||||
pragma solidity 0.4.23;
|
pragma solidity ^0.4.23;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
contract ValidatorRegistration {
|
contract ValidatorRegistration {
|
||||||
event ValidatorRegistered(
|
|
||||||
bytes32 indexed hashedPubkey,
|
event HashChainValue(
|
||||||
uint256 withdrawalShardID,
|
bytes indexed previousReceiptRoot,
|
||||||
address indexed withdrawalAddressbytes32,
|
bytes data,
|
||||||
bytes32 indexed randaoCommitment
|
uint totalDepositcount
|
||||||
);
|
);
|
||||||
|
|
||||||
mapping (bytes32 => bool) public usedHashedPubkey;
|
event ChainStart(
|
||||||
|
bytes indexed receiptRoot,
|
||||||
|
bytes time
|
||||||
|
);
|
||||||
|
|
||||||
uint public constant VALIDATOR_DEPOSIT = 32 ether;
|
uint public constant DEPOSIT_SIZE = 32 ether;
|
||||||
|
uint public constant DEPOSITS_FOR_CHAIN_START = 8;
|
||||||
|
uint public constant MIN_TOPUP_SIZE = 1 ether;
|
||||||
|
uint public constant GWEI_PER_ETH = 10 ** 9;
|
||||||
|
// Setting MERKLE_TREE_DEPTH to 16 instead of 32 due to gas limit
|
||||||
|
uint public constant MERKLE_TREE_DEPTH = 16;
|
||||||
|
uint public constant SECONDS_PER_DAY = 86400;
|
||||||
|
|
||||||
// Validator registers by sending a transaction of 32ETH to
|
mapping (uint => bytes) public receiptTree;
|
||||||
// the following deposit function. The deposit function takes in
|
uint public totalDepositCount;
|
||||||
// validator's public key, withdrawal shard ID (which shard
|
|
||||||
// to send the deposit back to), withdrawal address (which address
|
// When users wish to become a validator by moving ETH from
|
||||||
// to send the deposit back to) and randao commitment.
|
// 1.0 chian to the 2.0 chain, they should call this function
|
||||||
|
// sending along DEPOSIT_SIZE ETH and providing depositParams
|
||||||
|
// as a simple serialize'd DepositParams object of the following
|
||||||
|
// form:
|
||||||
|
// {
|
||||||
|
// 'pubkey': 'int256',
|
||||||
|
// 'proof_of_possession': ['int256'],
|
||||||
|
// 'withdrawal_credentials`: 'hash32',
|
||||||
|
// 'randao_commitment`: 'hash32'
|
||||||
|
// }
|
||||||
function deposit(
|
function deposit(
|
||||||
bytes _pubkey,
|
bytes depositParams
|
||||||
uint _withdrawalShardID,
|
|
||||||
address _withdrawalAddressbytes32,
|
|
||||||
bytes32 _randaoCommitment
|
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
payable
|
payable
|
||||||
{
|
{
|
||||||
|
uint index = totalDepositCount + 2 ** MERKLE_TREE_DEPTH;
|
||||||
|
bytes memory msgGweiInBytes = toBytes(msg.value);
|
||||||
|
bytes memory timeStampInBytes = toBytes(block.timestamp);
|
||||||
|
bytes memory depositData = mergeBytes(mergeBytes(msgGweiInBytes, timeStampInBytes), depositParams);
|
||||||
|
|
||||||
|
emit HashChainValue(receiptTree[1], depositParams, totalDepositCount);
|
||||||
|
|
||||||
|
receiptTree[index] = abi.encodePacked(keccak256(depositData));
|
||||||
|
for (uint i = 0; i < MERKLE_TREE_DEPTH; i++) {
|
||||||
|
index = index / 2;
|
||||||
|
receiptTree[index] = abi.encodePacked(keccak256(mergeBytes(receiptTree[index * 2], receiptTree[index * 2 + 1])));
|
||||||
|
}
|
||||||
|
|
||||||
require(
|
require(
|
||||||
msg.value == VALIDATOR_DEPOSIT,
|
msg.value <= DEPOSIT_SIZE,
|
||||||
"Incorrect validator deposit"
|
"Deposit can't be greater than DEPOSIT_SIZE."
|
||||||
);
|
);
|
||||||
require(
|
require(
|
||||||
_pubkey.length == 48,
|
msg.value >= MIN_TOPUP_SIZE,
|
||||||
"Public key is not 48 bytes"
|
"Deposit can't be lesser than MIN_TOPUP_SIZE."
|
||||||
);
|
);
|
||||||
|
if (msg.value == DEPOSIT_SIZE) {
|
||||||
|
totalDepositCount++;
|
||||||
|
}
|
||||||
|
|
||||||
bytes32 hashedPubkey = keccak256(abi.encodePacked(_pubkey));
|
// When ChainStart log publishes, beacon chain node initializes the chain and use timestampDayBoundry
|
||||||
require(
|
// as genesis time.
|
||||||
!usedHashedPubkey[hashedPubkey],
|
if (totalDepositCount == DEPOSITS_FOR_CHAIN_START) {
|
||||||
"Public key already used"
|
uint timestampDayBoundry = block.timestamp - block.timestamp % SECONDS_PER_DAY + SECONDS_PER_DAY;
|
||||||
);
|
bytes memory timestampDayBoundryBytes = toBytes(timestampDayBoundry);
|
||||||
|
emit ChainStart(receiptTree[1], timestampDayBoundryBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
usedHashedPubkey[hashedPubkey] = true;
|
function getReceiptRoot() public constant returns (bytes) {
|
||||||
|
return receiptTree[1];
|
||||||
|
}
|
||||||
|
|
||||||
emit ValidatorRegistered(hashedPubkey, _withdrawalShardID, _withdrawalAddressbytes32, _randaoCommitment);
|
function toBytes(uint x) private constant returns (bytes memory) {
|
||||||
|
bytes memory b = new bytes(32);
|
||||||
|
assembly { mstore(add(b, 32), x) }
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeBytes(bytes memory a, bytes memory b) private returns (bytes memory c) {
|
||||||
|
// Store the length of the first array
|
||||||
|
uint alen = a.length;
|
||||||
|
// Store the length of BOTH arrays
|
||||||
|
uint totallen = alen + b.length;
|
||||||
|
// Count the loops required for array a (sets of 32 bytes)
|
||||||
|
uint loopsa = (a.length + 31) / 32;
|
||||||
|
// Count the loops required for array b (sets of 32 bytes)
|
||||||
|
uint loopsb = (b.length + 31) / 32;
|
||||||
|
assembly {
|
||||||
|
let m := mload(0x40)
|
||||||
|
// Load the length of both arrays to the head of the new bytes array
|
||||||
|
mstore(m, totallen)
|
||||||
|
// Add the contents of a to the array
|
||||||
|
for { let i := 0 } lt(i, loopsa) { i := add(1, i) } { mstore(add(m, mul(32, add(1, i))), mload(add(a, mul(32, add(1, i))))) }
|
||||||
|
// Add the contents of b to the array
|
||||||
|
for { let i := 0 } lt(i, loopsb) { i := add(1, i) } { mstore(add(m, add(mul(32, add(1, i)), alen)), mload(add(b, mul(32, add(1, i))))) }
|
||||||
|
mstore(0x40, add(m, add(32, totallen)))
|
||||||
|
c := m
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package vrc
|
package vrc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -15,19 +16,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
amount33Eth, _ = new(big.Int).SetString("33000000000000000000", 10)
|
amount33Eth, _ = new(big.Int).SetString("33000000000000000000", 10)
|
||||||
amount32Eth, _ = new(big.Int).SetString("32000000000000000000", 10)
|
amount32Eth, _ = new(big.Int).SetString("32000000000000000000", 10)
|
||||||
amount31Eth, _ = new(big.Int).SetString("31000000000000000000", 10)
|
amountLessThan1Eth, _ = new(big.Int).SetString("500000000000000000", 10)
|
||||||
)
|
)
|
||||||
|
|
||||||
type testAccount struct {
|
type testAccount struct {
|
||||||
addr common.Address
|
addr common.Address
|
||||||
withdrawalAddress common.Address
|
contract *ValidatorRegistration
|
||||||
randaoCommitment [32]byte
|
backend *backends.SimulatedBackend
|
||||||
pubKey []byte
|
txOpts *bind.TransactOpts
|
||||||
contract *ValidatorRegistration
|
|
||||||
backend *backends.SimulatedBackend
|
|
||||||
txOpts *bind.TransactOpts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup() (*testAccount, error) {
|
func setup() (*testAccount, error) {
|
||||||
@ -45,7 +43,7 @@ func setup() (*testAccount, error) {
|
|||||||
|
|
||||||
addr := crypto.PubkeyToAddress(privKey.PublicKey)
|
addr := crypto.PubkeyToAddress(privKey.PublicKey)
|
||||||
txOpts := bind.NewKeyedTransactor(privKey)
|
txOpts := bind.NewKeyedTransactor(privKey)
|
||||||
startingBalance, _ := new(big.Int).SetString("100000000000000000000", 10)
|
startingBalance, _ := new(big.Int).SetString("1000000000000000000000", 10)
|
||||||
genesis[addr] = core.GenesisAccount{Balance: startingBalance}
|
genesis[addr] = core.GenesisAccount{Balance: startingBalance}
|
||||||
backend := backends.NewSimulatedBackend(genesis, 2100000)
|
backend := backends.NewSimulatedBackend(genesis, 2100000)
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ func setup() (*testAccount, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &testAccount{addr, common.Address{}, [32]byte{}, pubKey, contract, backend, txOpts}, nil
|
return &testAccount{addr, contract, backend, txOpts}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetupAndContractRegistration(t *testing.T) {
|
func TestSetupAndContractRegistration(t *testing.T) {
|
||||||
@ -64,100 +62,58 @@ func TestSetupAndContractRegistration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// negative test case, public key that is not 48 bytes.
|
// negative test case, deposit with less than 1 ETH which is less than the top off amount.
|
||||||
func TestRegisterWithLessThan48BytesPubkey(t *testing.T) {
|
func TestRegisterWithLessThan1Eth(t *testing.T) {
|
||||||
testAccount, err := setup()
|
testAccount, err := setup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
var pubKey = make([]byte, 32)
|
|
||||||
copy(pubKey, testAccount.pubKey[:])
|
|
||||||
withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'}
|
|
||||||
randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'}
|
|
||||||
|
|
||||||
testAccount.txOpts.Value = amount32Eth
|
testAccount.txOpts.Value = amountLessThan1Eth
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment)
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{})
|
||||||
if err == nil {
|
|
||||||
t.Error("Validator registration should have failed with a 32 bytes pubkey")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// negative test case, deposit with less than 32 ETH.
|
|
||||||
func TestRegisterWithLessThan32Eth(t *testing.T) {
|
|
||||||
testAccount, err := setup()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'}
|
|
||||||
randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'}
|
|
||||||
|
|
||||||
testAccount.txOpts.Value = amount31Eth
|
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Validator registration should have failed with insufficient deposit")
|
t.Error("Validator registration should have failed with insufficient deposit")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// negative test case, deposit more than 32 ETH.
|
// negative test case, deposit with more than 32 ETH which is more than the asked amount.
|
||||||
func TestRegisterWithMoreThan32Eth(t *testing.T) {
|
func TestRegisterWithMoreThan32Eth(t *testing.T) {
|
||||||
testAccount, err := setup()
|
testAccount, err := setup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'}
|
|
||||||
randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'}
|
|
||||||
|
|
||||||
testAccount.txOpts.Value = amount33Eth
|
testAccount.txOpts.Value = amount33Eth
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment)
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Validator registration should have failed with more than deposit amount")
|
t.Error("Validator registration should have failed with more than asked deposit amount")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// negative test case, test registering with the same public key twice.
|
// normal test case, test depositing 32 ETH and verify HashChainValue event is correctly emitted.
|
||||||
func TestRegisterTwice(t *testing.T) {
|
func TestValidatorRegisters(t *testing.T) {
|
||||||
testAccount, err := setup()
|
testAccount, err := setup()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'}
|
|
||||||
randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'}
|
|
||||||
|
|
||||||
testAccount.txOpts.Value = amount32Eth
|
testAccount.txOpts.Value = amount32Eth
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment)
|
|
||||||
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'A'})
|
||||||
testAccount.backend.Commit()
|
testAccount.backend.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Validator registration failed: %v", err)
|
t.Errorf("Validator registration failed: %v", err)
|
||||||
}
|
}
|
||||||
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'B'})
|
||||||
testAccount.txOpts.Value = amount32Eth
|
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, big.NewInt(0), *withdrawAddr, *randaoCommitment)
|
|
||||||
testAccount.backend.Commit()
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Registration should have failed with same public key twice")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// normal test case, test depositing 32 ETH and verify validatorRegistered event is correctly emitted.
|
|
||||||
func TestRegister(t *testing.T) {
|
|
||||||
testAccount, err := setup()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
withdrawAddr := &common.Address{'A', 'D', 'D', 'R', 'E', 'S', 'S'}
|
|
||||||
randaoCommitment := &[32]byte{'S', 'H', 'H', 'H', 'H', 'I', 'T', 'S', 'A', 'S', 'E', 'C', 'R', 'E', 'T'}
|
|
||||||
shardID := big.NewInt(99)
|
|
||||||
testAccount.txOpts.Value = amount32Eth
|
|
||||||
|
|
||||||
var hashedPub [32]byte
|
|
||||||
copy(hashedPub[:], crypto.Keccak256(testAccount.pubKey))
|
|
||||||
|
|
||||||
_, err = testAccount.contract.Deposit(testAccount.txOpts, testAccount.pubKey, shardID, *withdrawAddr, *randaoCommitment)
|
|
||||||
testAccount.backend.Commit()
|
testAccount.backend.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Validator registration failed: %v", err)
|
t.Errorf("Validator registration failed: %v", err)
|
||||||
}
|
}
|
||||||
log, err := testAccount.contract.FilterValidatorRegistered(&bind.FilterOpts{}, [][32]byte{}, []common.Address{}, [][32]byte{})
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'C'})
|
||||||
|
testAccount.backend.Commit()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Validator registration failed: %v", err)
|
||||||
|
}
|
||||||
|
log, err := testAccount.contract.FilterHashChainValue(&bind.FilterOpts{}, [][]byte{})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = log.Close()
|
err = log.Close()
|
||||||
@ -173,16 +129,65 @@ func TestRegister(t *testing.T) {
|
|||||||
t.Fatal(log.Error())
|
t.Fatal(log.Error())
|
||||||
}
|
}
|
||||||
log.Next()
|
log.Next()
|
||||||
if log.Event.WithdrawalShardID.Cmp(shardID) != 0 {
|
|
||||||
t.Errorf("validatorRegistered event withdrawal shard ID miss matched. Want: %v, Got: %v", shardID, log.Event.WithdrawalShardID)
|
if log.Event.TotalDepositcount.Cmp(big.NewInt(0)) != 0 {
|
||||||
|
t.Errorf("HashChainValue event total desposit count miss matched. Want: %v, Got: %v", big.NewInt(0), log.Event.TotalDepositcount)
|
||||||
}
|
}
|
||||||
if log.Event.RandaoCommitment != *randaoCommitment {
|
if !bytes.Equal(log.Event.Data, []byte{'A'}) {
|
||||||
t.Errorf("validatorRegistered event randao commitment miss matched. Want: %v, Got: %v", *randaoCommitment, log.Event.RandaoCommitment)
|
t.Errorf("validatorRegistered event randao commitment miss matched. Want: %v, Got: %v", []byte{'A'}, log.Event.Data)
|
||||||
}
|
}
|
||||||
if log.Event.HashedPubkey != hashedPub {
|
|
||||||
t.Errorf("validatorRegistered event public key miss matched. Want: %v, Got: %v", common.BytesToHash(testAccount.pubKey), log.Event.HashedPubkey)
|
log.Next()
|
||||||
|
if log.Event.TotalDepositcount.Cmp(big.NewInt(1)) != 0 {
|
||||||
|
t.Errorf("HashChainValue event total desposit count miss matched. Want: %v, Got: %v", big.NewInt(1), log.Event.TotalDepositcount)
|
||||||
}
|
}
|
||||||
if log.Event.WithdrawalAddressbytes32 != *withdrawAddr {
|
if !bytes.Equal(log.Event.Data, []byte{'B'}) {
|
||||||
t.Errorf("validatorRegistered event withdrawal address miss matched. Want: %v, Got: %v", *withdrawAddr, log.Event.WithdrawalAddressbytes32)
|
t.Errorf("validatorRegistered event randao commitment miss matched. Want: %v, Got: %v", []byte{'B'}, log.Event.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Next()
|
||||||
|
if log.Event.TotalDepositcount.Cmp(big.NewInt(2)) != 0 {
|
||||||
|
t.Errorf("HashChainValue event total desposit count miss matched. Want: %v, Got: %v", big.NewInt(1), log.Event.TotalDepositcount)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(log.Event.Data, []byte{'C'}) {
|
||||||
|
t.Errorf("validatorRegistered event randao commitment miss matched. Want: %v, Got: %v", []byte{'B'}, log.Event.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal test case, test beacon chain start log event.
|
||||||
|
func TestChainStarts(t *testing.T) {
|
||||||
|
testAccount, err := setup()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
testAccount.txOpts.Value = amount32Eth
|
||||||
|
|
||||||
|
for i := 0; i < 9; i++ {
|
||||||
|
_, err = testAccount.contract.Deposit(testAccount.txOpts, []byte{'A'})
|
||||||
|
testAccount.backend.Commit()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Validator registration failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log, err := testAccount.contract.FilterChainStart(&bind.FilterOpts{}, [][]byte{})
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = log.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if log.Error() != nil {
|
||||||
|
t.Fatal(log.Error())
|
||||||
|
}
|
||||||
|
log.Next()
|
||||||
|
|
||||||
|
if len(log.Event.Time) == 0 {
|
||||||
|
t.Error("Chain start even did not get emitted, The start time is empty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user