mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Add in ChainStart Listener (#1327)
* changing handling of logs * gazelle * removing outdated vars * fixing tests * adding vrc bindings to service * updating vrc sol and bindings * more changes * adding trie * remove functions * addressing preston's review * tests * gazelle * fixed tests * note * Lint * doc * exploration test * adding new methods and tests * adding log type checker * lint * Adding processChainstartLog * gazelle * addressing comments * addressing comments and adding tests * review comments * comment * comment * abi naming
This commit is contained in:
@@ -111,20 +111,20 @@ func setupBeaconChain(t *testing.T, faultyPoWClient bool, beaconDB *db.BeaconDB)
|
||||
if faultyPoWClient {
|
||||
client := &faultyClient{}
|
||||
web3Service, err = powchain.NewWeb3Service(ctx, &powchain.Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: client,
|
||||
Client: client,
|
||||
Logger: client,
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: client,
|
||||
Client: client,
|
||||
Logger: client,
|
||||
})
|
||||
} else {
|
||||
client := &mockClient{}
|
||||
web3Service, err = powchain.NewWeb3Service(ctx, &powchain.Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: client,
|
||||
Client: client,
|
||||
Logger: client,
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: client,
|
||||
Client: client,
|
||||
Logger: client,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -274,7 +274,7 @@ func (b *BeaconNode) registerPOWChainService(ctx *cli.Context) error {
|
||||
|
||||
web3Service, err := powchain.NewWeb3Service(context.TODO(), &powchain.Web3ServiceConfig{
|
||||
Endpoint: b.ctx.GlobalString(utils.Web3ProviderFlag.Name),
|
||||
VrcAddr: common.HexToAddress(b.ctx.GlobalString(utils.VrcContractFlag.Name)),
|
||||
DepositContract: common.HexToAddress(b.ctx.GlobalString(utils.VrcContractFlag.Name)),
|
||||
Client: powClient,
|
||||
Reader: powClient,
|
||||
Logger: powClient,
|
||||
|
||||
@@ -7,11 +7,11 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//contracts/validator-registration-contract:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/trie:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//accounts/abi:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//accounts/abi/bind:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
@@ -25,6 +25,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//contracts/validator-registration-contract:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
package powchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
contracts "github.com/prysmaticlabs/prysm/contracts/validator-registration-contract"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/trie"
|
||||
@@ -50,27 +50,27 @@ type Client interface {
|
||||
// Validator Registration Contract on the PoW chain to kick off the beacon
|
||||
// chain's validator registration process.
|
||||
type Web3Service struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
client Client
|
||||
headerChan chan *gethTypes.Header
|
||||
logChan chan gethTypes.Log
|
||||
endpoint string
|
||||
vrcAddress common.Address
|
||||
reader Reader
|
||||
logger bind.ContractFilterer
|
||||
blockNumber *big.Int // the latest PoW chain blockNumber.
|
||||
blockHash common.Hash // the latest PoW chain blockHash.
|
||||
vrcCaller *contracts.ValidatorRegistrationCaller
|
||||
depositCount uint64
|
||||
depositRoot []byte
|
||||
depositTrie *trie.DepositTrie
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
client Client
|
||||
headerChan chan *gethTypes.Header
|
||||
logChan chan gethTypes.Log
|
||||
endpoint string
|
||||
depositContractAddress common.Address
|
||||
reader Reader
|
||||
logger bind.ContractFilterer
|
||||
blockNumber *big.Int // the latest PoW chain blockNumber.
|
||||
blockHash common.Hash // the latest PoW chain blockHash.
|
||||
vrcCaller *contracts.ValidatorRegistrationCaller
|
||||
depositCount uint64
|
||||
depositRoot []byte
|
||||
depositTrie *trie.DepositTrie
|
||||
}
|
||||
|
||||
// Web3ServiceConfig defines a config struct for web3 service to use through its life cycle.
|
||||
type Web3ServiceConfig struct {
|
||||
Endpoint string
|
||||
VrcAddr common.Address
|
||||
DepositContract common.Address
|
||||
Client Client
|
||||
Reader Reader
|
||||
Logger bind.ContractFilterer
|
||||
@@ -79,7 +79,7 @@ type Web3ServiceConfig struct {
|
||||
|
||||
var (
|
||||
depositEventSignature = []byte("Deposit(bytes,bytes,bytes)")
|
||||
chainStartEventSignature = []byte("ChainStart(bytes,bytes,bytes)")
|
||||
chainStartEventSignature = []byte("ChainStart(bytes,bytes)")
|
||||
)
|
||||
|
||||
// NewWeb3Service sets up a new instance with an ethclient when
|
||||
@@ -92,25 +92,25 @@ func NewWeb3Service(ctx context.Context, config *Web3ServiceConfig) (*Web3Servic
|
||||
)
|
||||
}
|
||||
|
||||
vrcCaller, err := contracts.NewValidatorRegistrationCaller(config.VrcAddr, config.ContractBackend)
|
||||
vrcCaller, err := contracts.NewValidatorRegistrationCaller(config.DepositContract, config.ContractBackend)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create VRC caller %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Web3Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
headerChan: make(chan *gethTypes.Header),
|
||||
logChan: make(chan gethTypes.Log),
|
||||
endpoint: config.Endpoint,
|
||||
blockNumber: nil,
|
||||
blockHash: common.BytesToHash([]byte{}),
|
||||
vrcAddress: config.VrcAddr,
|
||||
client: config.Client,
|
||||
reader: config.Reader,
|
||||
logger: config.Logger,
|
||||
vrcCaller: vrcCaller,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
headerChan: make(chan *gethTypes.Header),
|
||||
logChan: make(chan gethTypes.Log),
|
||||
endpoint: config.Endpoint,
|
||||
blockNumber: nil,
|
||||
blockHash: common.BytesToHash([]byte{}),
|
||||
depositContractAddress: config.DepositContract,
|
||||
client: config.Client,
|
||||
reader: config.Reader,
|
||||
logger: config.Logger,
|
||||
vrcCaller: vrcCaller,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ func (w *Web3Service) run(done <-chan struct{}) {
|
||||
}
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
w.vrcAddress,
|
||||
w.depositContractAddress,
|
||||
},
|
||||
}
|
||||
logSub, err := w.logger.SubscribeFilterLogs(w.ctx, query, w.logChan)
|
||||
@@ -206,88 +206,78 @@ func (w *Web3Service) run(done <-chan struct{}) {
|
||||
"blockHash": w.blockHash.Hex(),
|
||||
}).Debug("Latest web3 chain event")
|
||||
case VRClog := <-w.logChan:
|
||||
w.processLog(VRClog)
|
||||
w.ProcessLog(VRClog)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Web3Service) processLog(VRClog gethTypes.Log) {
|
||||
// ProcessLog is the main method which handles the processing of all
|
||||
// logs from the deposit contract on the POW Chain.
|
||||
func (w *Web3Service) ProcessLog(VRClog gethTypes.Log) {
|
||||
// Process logs according to their event signature.
|
||||
if VRClog.Topics[0] == hashutil.Hash(depositEventSignature) {
|
||||
w.processDepositLog(VRClog)
|
||||
w.ProcessDepositLog(VRClog)
|
||||
return
|
||||
}
|
||||
|
||||
if VRClog.Topics[0] == hashutil.Hash(chainStartEventSignature) {
|
||||
w.processChainStartLog(VRClog)
|
||||
w.ProcessChainStartLog(VRClog)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Log is not of a valid event signature %#x", VRClog.Topics[0])
|
||||
}
|
||||
|
||||
// processDepositLog processes the log which had been received from
|
||||
// ProcessDepositLog processes the log which had been received from
|
||||
// the POW chain by trying to ascertain which participant deposited
|
||||
// in the contract.
|
||||
func (w *Web3Service) processDepositLog(VRClog gethTypes.Log) {
|
||||
|
||||
func (w *Web3Service) ProcessDepositLog(VRClog gethTypes.Log) {
|
||||
merkleRoot := VRClog.Topics[1]
|
||||
depositData, MerkleTreeIndex, err := w.unPackLogData(VRClog.Data)
|
||||
depositData, MerkleTreeIndex, err := utils.UnpackDepositLogData(VRClog.Data)
|
||||
if err != nil {
|
||||
log.Errorf("Could not unpack log %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := w.saveInTrie(depositData, merkleRoot); err != nil {
|
||||
log.Errorf("Could not save in trie %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
depositInput, err := blocks.DecodeDepositInput(depositData)
|
||||
if err != nil {
|
||||
log.Errorf("Could not decode deposit input %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
index := binary.BigEndian.Uint64(MerkleTreeIndex)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"publicKey": depositInput.Pubkey,
|
||||
"merkle tree index": index,
|
||||
}).Info("Validator registered in VRC with public key and index")
|
||||
|
||||
}
|
||||
|
||||
// processChainStartLog processes the log which had been received from
|
||||
// ProcessChainStartLog processes the log which had been received from
|
||||
// the POW chain by trying to determine when to start the beacon chain.
|
||||
func (w *Web3Service) processChainStartLog(VRClog gethTypes.Log) {
|
||||
_ = VRClog
|
||||
//TODO(#1288): Process ChainStart Logs.
|
||||
}
|
||||
|
||||
// unPackLogData unpacks the data from a log using the abi decoder.
|
||||
func (w *Web3Service) unPackLogData(data []byte) ([]byte, []byte, error) {
|
||||
|
||||
reader := bytes.NewReader([]byte(contracts.ValidatorRegistrationABI))
|
||||
contractAbi, err := abi.JSON(reader)
|
||||
func (w *Web3Service) ProcessChainStartLog(VRClog gethTypes.Log) {
|
||||
receiptRoot := VRClog.Topics[1]
|
||||
timestampData, err := utils.UnpackChainStartLogData(VRClog.Data)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to generate contract abi %v", err)
|
||||
log.Errorf("Unable to unpack ChainStart log data %v", err)
|
||||
return
|
||||
}
|
||||
if w.depositTrie.Root() != receiptRoot {
|
||||
log.Errorf("Receipt root from log doesn't match the root saved in memory %#x", receiptRoot)
|
||||
return
|
||||
}
|
||||
|
||||
unpackedLogs := []*[]byte{
|
||||
&[]byte{},
|
||||
&[]byte{},
|
||||
timestamp := binary.BigEndian.Uint64(timestampData)
|
||||
if uint64(time.Now().Unix()) < timestamp {
|
||||
log.Errorf("Invalid timestamp from log expected %d > %d", time.Now().Unix(), timestamp)
|
||||
}
|
||||
|
||||
if err := contractAbi.Unpack(&unpackedLogs, "Deposit", data); err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to unpack logs %v", err)
|
||||
}
|
||||
|
||||
depositData := *unpackedLogs[0]
|
||||
merkleTreeIndex := *unpackedLogs[1]
|
||||
|
||||
return depositData, merkleTreeIndex, nil
|
||||
chainStartTime := time.Unix(int64(timestamp), 0)
|
||||
log.WithFields(logrus.Fields{
|
||||
"ChainStartTime": chainStartTime,
|
||||
}).Info("Minimum Number of Validators Reached for beacon-chain to start")
|
||||
}
|
||||
|
||||
// saveInTrie saves in the in-memory deposit trie.
|
||||
@@ -300,6 +290,8 @@ func (w *Web3Service) saveInTrie(depositData []byte, merkleRoot common.Hash) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// processPastLogs processes all the past logs from the deposit contract and
|
||||
// updates the deposit trie with the data from each individual log.
|
||||
func (w *Web3Service) processPastLogs(query ethereum.FilterQuery) error {
|
||||
logs, err := w.logger.FilterLogs(w.ctx, query)
|
||||
if err != nil {
|
||||
@@ -307,7 +299,7 @@ func (w *Web3Service) processPastLogs(query ethereum.FilterQuery) error {
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
w.processLog(log)
|
||||
w.ProcessLog(log)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
contracts "github.com/prysmaticlabs/prysm/contracts/validator-registration-contract"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
@@ -111,37 +113,37 @@ func TestNewWeb3Service(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
var err error
|
||||
if _, err = NewWeb3Service(ctx, &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
}); err == nil {
|
||||
t.Errorf("passing in an HTTP endpoint should throw an error, received nil")
|
||||
}
|
||||
endpoint = "ftp://127.0.0.1"
|
||||
if _, err = NewWeb3Service(ctx, &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
}); err == nil {
|
||||
t.Errorf("passing in a non-ws, wss, or ipc endpoint should throw an error, received nil")
|
||||
}
|
||||
endpoint = "ws://127.0.0.1"
|
||||
if _, err = NewWeb3Service(ctx, &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
}); err != nil {
|
||||
t.Errorf("passing in as ws endpoint should not throw error, received %v", err)
|
||||
}
|
||||
endpoint = "ipc://geth.ipc"
|
||||
if _, err = NewWeb3Service(ctx, &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
Endpoint: endpoint,
|
||||
DepositContract: common.Address{},
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
}); err != nil {
|
||||
t.Errorf("passing in an ipc endpoint should not throw error, received %v", err)
|
||||
}
|
||||
@@ -157,7 +159,7 @@ func TestStart(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -188,7 +190,7 @@ func TestStop(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -224,7 +226,7 @@ func TestInitDataFromVRC(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -275,7 +277,7 @@ func TestSaveInTrie(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -296,76 +298,6 @@ func TestSaveInTrie(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestProcessDepositLog(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
endpoint := "ws://127.0.0.1"
|
||||
testAcc, err := setup()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to set up simulated backend %v", err)
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to setup web3 PoW chain service: %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
|
||||
web3Service.depositTrie = trie.NewDepositTrie()
|
||||
|
||||
currentRoot := web3Service.depositTrie.Root()
|
||||
|
||||
var stub [48]byte
|
||||
copy(stub[:], []byte("testing"))
|
||||
|
||||
data := &pb.DepositInput{
|
||||
Pubkey: stub[:],
|
||||
ProofOfPossession: stub[:],
|
||||
WithdrawalCredentialsHash32: []byte("withdraw"),
|
||||
RandaoCommitmentHash32: []byte("randao"),
|
||||
CustodyCommitmentHash32: []byte("custody"),
|
||||
}
|
||||
|
||||
serializedData := new(bytes.Buffer)
|
||||
if err := ssz.Encode(serializedData, data); err != nil {
|
||||
t.Fatalf("Could not serialize data %v", err)
|
||||
}
|
||||
|
||||
testAcc.txOpts.Value = amount32Eth
|
||||
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
|
||||
t.Fatalf("Could not deposit to VRC %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
web3Service.vrcAddress,
|
||||
},
|
||||
}
|
||||
|
||||
logs, err := testAcc.backend.FilterLogs(web3Service.ctx, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to retrieve logs %v", err)
|
||||
}
|
||||
|
||||
logs[0].Topics[1] = currentRoot
|
||||
|
||||
web3Service.processLog(logs[0])
|
||||
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not unpack log")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not save in trie")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not decode deposit input")
|
||||
testutil.AssertLogsContain(t, hook, "Validator registered in VRC with public key and index")
|
||||
|
||||
hook.Reset()
|
||||
}
|
||||
|
||||
func TestBadReader(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
endpoint := "ws://127.0.0.1"
|
||||
@@ -375,7 +307,7 @@ func TestBadReader(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &badReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -404,7 +336,7 @@ func TestLatestMainchainInfo(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -447,7 +379,7 @@ func TestBadLogger(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -469,7 +401,8 @@ func TestBadLogger(t *testing.T) {
|
||||
hook.Reset()
|
||||
}
|
||||
|
||||
func TestUnpackLogs(t *testing.T) {
|
||||
func TestProcessDepositLog(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
endpoint := "ws://127.0.0.1"
|
||||
testAcc, err := setup()
|
||||
if err != nil {
|
||||
@@ -477,7 +410,76 @@ func TestUnpackLogs(t *testing.T) {
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
VrcAddr: testAcc.contractAddr,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to setup web3 PoW chain service: %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
|
||||
web3Service.depositTrie = trie.NewDepositTrie()
|
||||
|
||||
currentRoot := web3Service.depositTrie.Root()
|
||||
|
||||
var stub [48]byte
|
||||
copy(stub[:], []byte("testing"))
|
||||
|
||||
data := &pb.DepositInput{
|
||||
Pubkey: stub[:],
|
||||
ProofOfPossession: stub[:],
|
||||
WithdrawalCredentialsHash32: []byte("withdraw"),
|
||||
RandaoCommitmentHash32: []byte("randao"),
|
||||
CustodyCommitmentHash32: []byte("custody"),
|
||||
}
|
||||
|
||||
serializedData := new(bytes.Buffer)
|
||||
if err := ssz.Encode(serializedData, data); err != nil {
|
||||
t.Fatalf("Could not serialize data %v", err)
|
||||
}
|
||||
|
||||
testAcc.txOpts.Value = amount32Eth
|
||||
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
|
||||
t.Fatalf("Could not deposit to VRC %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
web3Service.depositContractAddress,
|
||||
},
|
||||
}
|
||||
|
||||
logs, err := testAcc.backend.FilterLogs(web3Service.ctx, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to retrieve logs %v", err)
|
||||
}
|
||||
|
||||
logs[0].Topics[1] = currentRoot
|
||||
|
||||
web3Service.ProcessLog(logs[0])
|
||||
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not unpack log")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not save in trie")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Could not decode deposit input")
|
||||
testutil.AssertLogsContain(t, hook, "Validator registered in VRC with public key and index")
|
||||
|
||||
hook.Reset()
|
||||
}
|
||||
|
||||
func TestUnpackDepositLogs(t *testing.T) {
|
||||
endpoint := "ws://127.0.0.1"
|
||||
testAcc, err := setup()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to set up simulated backend %v", err)
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
@@ -524,7 +526,7 @@ func TestUnpackLogs(t *testing.T) {
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
web3Service.vrcAddress,
|
||||
web3Service.depositContractAddress,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -533,7 +535,7 @@ func TestUnpackLogs(t *testing.T) {
|
||||
t.Fatalf("Unable to retrieve logs %v", err)
|
||||
}
|
||||
|
||||
depData, index, err := web3Service.unPackLogData(logz[0].Data)
|
||||
depData, index, err := utils.UnpackDepositLogData(logz[0].Data)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to unpack logs %v", err)
|
||||
}
|
||||
@@ -568,3 +570,152 @@ func TestUnpackLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestProcessChainStartLog(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
endpoint := "ws://127.0.0.1"
|
||||
testAcc, err := setup()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to set up simulated backend %v", err)
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to setup web3 PoW chain service: %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
testAcc.backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
|
||||
|
||||
web3Service.depositTrie = trie.NewDepositTrie()
|
||||
|
||||
currentRoot := web3Service.depositTrie.Root()
|
||||
|
||||
var stub [48]byte
|
||||
copy(stub[:], []byte("testing"))
|
||||
|
||||
data := &pb.DepositInput{
|
||||
Pubkey: stub[:],
|
||||
ProofOfPossession: stub[:],
|
||||
WithdrawalCredentialsHash32: []byte("withdraw"),
|
||||
RandaoCommitmentHash32: []byte("randao"),
|
||||
CustodyCommitmentHash32: []byte("custody"),
|
||||
}
|
||||
|
||||
serializedData := new(bytes.Buffer)
|
||||
if err := ssz.Encode(serializedData, data); err != nil {
|
||||
t.Fatalf("Could not serialize data %v", err)
|
||||
}
|
||||
|
||||
// 8 Validators are used as size required for beacon-chain to start. This number
|
||||
// is defined in the VRC as the number required for the testnet. The actual number
|
||||
// is 2**14
|
||||
for i := 0; i < 8; i++ {
|
||||
testAcc.txOpts.Value = amount32Eth
|
||||
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
|
||||
t.Fatalf("Could not deposit to VRC %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
}
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
web3Service.depositContractAddress,
|
||||
},
|
||||
}
|
||||
|
||||
logs, err := testAcc.backend.FilterLogs(web3Service.ctx, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to retrieve logs %v", err)
|
||||
}
|
||||
|
||||
logs[len(logs)-1].Topics[1] = currentRoot
|
||||
|
||||
web3Service.ProcessLog(logs[len(logs)-1])
|
||||
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Unable to unpack ChainStart log data")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Receipt root from log doesn't match the root saved in memory")
|
||||
testutil.AssertLogsDoNotContain(t, hook, "Invalid timestamp from log")
|
||||
testutil.AssertLogsContain(t, hook, "Minimum Number of Validators Reached for beacon-chain to start")
|
||||
|
||||
hook.Reset()
|
||||
|
||||
}
|
||||
|
||||
func TestUnpackChainStartLogs(t *testing.T) {
|
||||
endpoint := "ws://127.0.0.1"
|
||||
testAcc, err := setup()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to set up simulated backend %v", err)
|
||||
}
|
||||
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
|
||||
Endpoint: endpoint,
|
||||
DepositContract: testAcc.contractAddr,
|
||||
Reader: &goodReader{},
|
||||
Logger: &goodLogger{},
|
||||
ContractBackend: testAcc.backend,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to setup web3 PoW chain service: %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
|
||||
testAcc.backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
|
||||
|
||||
var stub [48]byte
|
||||
copy(stub[:], []byte("testing"))
|
||||
|
||||
data := &pb.DepositInput{
|
||||
Pubkey: stub[:],
|
||||
ProofOfPossession: stub[:],
|
||||
WithdrawalCredentialsHash32: []byte("withdraw"),
|
||||
RandaoCommitmentHash32: []byte("randao"),
|
||||
CustodyCommitmentHash32: []byte("custody"),
|
||||
}
|
||||
|
||||
serializedData := new(bytes.Buffer)
|
||||
if err := ssz.Encode(serializedData, data); err != nil {
|
||||
t.Fatalf("Could not serialize data %v", err)
|
||||
}
|
||||
|
||||
// 8 Validators are used as size required for beacon-chain to start. This number
|
||||
// is defined in the VRC as the number required for the testnet.
|
||||
for i := 0; i < 8; i++ {
|
||||
testAcc.txOpts.Value = amount32Eth
|
||||
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
|
||||
t.Fatalf("Could not deposit to VRC %v", err)
|
||||
}
|
||||
|
||||
testAcc.backend.Commit()
|
||||
}
|
||||
|
||||
query := ethereum.FilterQuery{
|
||||
Addresses: []common.Address{
|
||||
web3Service.depositContractAddress,
|
||||
},
|
||||
}
|
||||
|
||||
logs, err := testAcc.backend.FilterLogs(web3Service.ctx, query)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to retrieve logs %v", err)
|
||||
}
|
||||
|
||||
timestampData, err := utils.UnpackChainStartLogData(logs[len(logs)-1].Data)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to unpack logs %v", err)
|
||||
}
|
||||
|
||||
timestamp := binary.BigEndian.Uint64(timestampData)
|
||||
|
||||
if timestamp > uint64(time.Now().Unix()) {
|
||||
t.Errorf("Timestamp from log is higher than the current time %d > %d", timestamp, time.Now().Unix())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"POWlogs.go",
|
||||
"block_vote_cache.go",
|
||||
"clock.go",
|
||||
"flags.go",
|
||||
@@ -11,8 +12,10 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/utils",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//contracts/validator-registration-contract:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//accounts/abi:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_urfave_cli//:go_default_library",
|
||||
],
|
||||
|
||||
46
beacon-chain/utils/POWlogs.go
Normal file
46
beacon-chain/utils/POWlogs.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
contracts "github.com/prysmaticlabs/prysm/contracts/validator-registration-contract"
|
||||
)
|
||||
|
||||
// UnpackDepositLogData unpacks the data from a deposit log using the ABI decoder.
|
||||
func UnpackDepositLogData(data []byte) (depositData []byte, merkleTreeIndex []byte, err error) {
|
||||
reader := bytes.NewReader([]byte(contracts.ValidatorRegistrationABI))
|
||||
contractAbi, err := abi.JSON(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to generate contract abi: %v", err)
|
||||
}
|
||||
unpackedLogs := []*[]byte{
|
||||
&[]byte{},
|
||||
&[]byte{},
|
||||
}
|
||||
if err := contractAbi.Unpack(&unpackedLogs, "Deposit", data); err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to unpack logs: %v", err)
|
||||
}
|
||||
depositData = *unpackedLogs[0]
|
||||
merkleTreeIndex = *unpackedLogs[1]
|
||||
|
||||
return depositData, merkleTreeIndex, nil
|
||||
}
|
||||
|
||||
// UnpackChainStartLogData unpacks the data from a chain start log using the ABI decoder.
|
||||
func UnpackChainStartLogData(data []byte) ([]byte, error) {
|
||||
reader := bytes.NewReader([]byte(contracts.ValidatorRegistrationABI))
|
||||
contractAbi, err := abi.JSON(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate contract abi: %v", err)
|
||||
}
|
||||
unpackedLogs := []*[]byte{
|
||||
&[]byte{},
|
||||
}
|
||||
if err := contractAbi.Unpack(&unpackedLogs, "ChainStart", data); err != nil {
|
||||
return nil, fmt.Errorf("unable to unpack logs: %v", err)
|
||||
}
|
||||
timestamp := *unpackedLogs[0]
|
||||
return timestamp, nil
|
||||
}
|
||||
Reference in New Issue
Block a user