Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Deposit Contract #2648

Merged
merged 24 commits into from
May 24, 2019
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions beacon-chain/blockchain/fork_choice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,14 @@ func TestAttestationTargets_RetrieveWorks(t *testing.T) {
}
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
log.Fatalf("could not hash block: %v", err)
t.Fatalf("could not hash block: %v", err)
}
if err := beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: []byte{},
}); err != nil {
log.Fatalf("could not save att tgt: %v", err)
t.Fatalf("could not save att tgt: %v", err)
}

attsService := attestation.NewAttestationService(
Expand Down
6 changes: 1 addition & 5 deletions beacon-chain/blockchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ func (c *ChainService) Start() {
// processChainStartTime initializes a series of deposits from the ChainStart deposits in the eth1
// deposit contract, initializes the beacon chain's state, and kicks off the beacon chain.
func (c *ChainService) processChainStartTime(genesisTime time.Time, chainStartSub event.Subscription) {
initialDepositsData := c.web3Service.ChainStartDeposits()
initialDeposits := make([]*pb.Deposit, len(initialDepositsData))
for i := range initialDepositsData {
initialDeposits[i] = &pb.Deposit{DepositData: initialDepositsData[i]}
}
initialDeposits := c.web3Service.ChainStartDeposits()

beaconState, err := c.initializeBeaconChain(genesisTime, initialDeposits, c.web3Service.ChainStartETH1Data())
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/powchain/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/powchain",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db:go_default_library",
"//contracts/deposit-contract:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
Expand Down
61 changes: 50 additions & 11 deletions beacon-chain/powchain/log_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"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/helpers"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/trieutil"
Expand Down Expand Up @@ -59,7 +59,7 @@ func (w *Web3Service) ProcessLog(depositLog gethTypes.Log) {
// the ETH1.0 chain by trying to ascertain which participant deposited
// in the contract.
func (w *Web3Service) ProcessDepositLog(depositLog gethTypes.Log) {
_, depositData, merkleTreeIndex, _, err := contracts.UnpackDepositLogData(depositLog.Data)
pubkey, withdrawalCredentials, amount, signature, merkleTreeIndex, err := contracts.UnpackDepositLogData(depositLog.Data)
if err != nil {
log.Errorf("Could not unpack log %v", err)
return
Expand All @@ -77,20 +77,39 @@ func (w *Web3Service) ProcessDepositLog(depositLog gethTypes.Log) {
// We then decode the deposit input in order to create a deposit object
// we can store in our persistent DB.
validData := true
depositInput, err := helpers.DecodeDepositInput(depositData)
depositData := &pb.DepositData{
Amount: bytesutil.FromBytes8(amount),
Pubkey: pubkey,
Signature: signature,
WithdrawalCredentials: withdrawalCredentials,
}

depositHash, err := hashutil.DepositHash(depositData)
if err != nil {
log.Errorf("Unable to determine hashed value of deposit %v", err)
return
}

if err := w.depositTrie.InsertIntoTrie(depositHash[:], int(index)); err != nil {
log.Errorf("Unable to insert deposit into trie %v", err)
return
}

proof, err := w.depositTrie.MerkleProof(int(index))
if err != nil {
log.Debugf("Could not decode deposit input %v", err)
validData = false
log.Errorf("Unable to generate merkle proof for deposit %v", err)
return
}

deposit := &pb.Deposit{
DepositData: depositData,
Index: index,
Data: depositData,
Index: index,
Proof: proof,
}

// Make sure duplicates are rejected pre-chainstart.
if !w.chainStarted && validData {
var pubkey = fmt.Sprintf("#%x", depositInput.Pubkey)
var pubkey = fmt.Sprintf("#%x", depositData.Pubkey)
if w.beaconDB.PubkeyInChainstart(w.ctx, pubkey) {
log.Warnf("Pubkey %#x has already been submitted for chainstart", pubkey)
} else {
Expand All @@ -102,13 +121,13 @@ func (w *Web3Service) ProcessDepositLog(depositLog gethTypes.Log) {
w.beaconDB.InsertDeposit(w.ctx, deposit, big.NewInt(int64(depositLog.BlockNumber)))

if !w.chainStarted {
w.chainStartDeposits = append(w.chainStartDeposits, depositData)
w.chainStartDeposits = append(w.chainStartDeposits, deposit)
} else {
w.beaconDB.InsertPendingDeposit(w.ctx, deposit, big.NewInt(int64(depositLog.BlockNumber)))
}
if validData {
log.WithFields(logrus.Fields{
"publicKey": fmt.Sprintf("%#x", depositInput.Pubkey),
"publicKey": fmt.Sprintf("%#x", depositData.Pubkey),
"merkleTreeIndex": index,
}).Debug("Deposit registered from deposit contract")
validDepositsCount.Inc()
Expand Down Expand Up @@ -139,11 +158,17 @@ func (w *Web3Service) ProcessChainStartLog(depositLog gethTypes.Log) {
w.depositRoot = chainStartDepositRoot[:]
chainStartTime := time.Unix(int64(timestamp), 0)

depHashes, err := w.ChainStartDepositHashes()
if err != nil {
log.Errorf("Generating chainstart deposit hashes failed: %v", err)
return
}

// We then update the in-memory deposit trie from the chain start
// deposits at this point, as this trie will be later needed for
// incoming, post-chain start deposits.
sparseMerkleTrie, err := trieutil.GenerateTrieFromItems(
w.chainStartDeposits,
depHashes,
int(params.BeaconConfig().DepositContractTreeDepth),
)
if err != nil {
Expand Down Expand Up @@ -216,3 +241,17 @@ func (w *Web3Service) requestBatchedLogs() error {
w.lastRequestedBlock.Set(requestedBlock)
return nil
}

// ChainStartDepositHashes returns the hashes of all the chainstart deposits
// stored in memory.
func (w *Web3Service) ChainStartDepositHashes() ([][]byte, error) {
hashes := make([][]byte, len(w.chainStartDeposits))
for i, dep := range w.chainStartDeposits {
hash, err := hashutil.DepositHash(dep.Data)
if err != nil {
return nil, err
}
hashes[i] = hash[:]
}
return hashes, nil
}
36 changes: 15 additions & 21 deletions beacon-chain/powchain/log_processing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,8 @@ func TestProcessDepositLog_OK(t *testing.T) {
WithdrawalCredentialsHash32: []byte("withdraw"),
}

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 {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

Expand Down Expand Up @@ -128,14 +123,13 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
}

testAcc.txOpts.Value = amount32Eth
badData := []byte("bad data")
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

// A deposit with bad data should also be correctly processed and added to the
// db in the pending deposits bucket.
if _, err := testAcc.contract.Deposit(testAcc.txOpts, badData); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

Expand Down Expand Up @@ -202,7 +196,7 @@ func TestUnpackDepositLogData_OK(t *testing.T) {
}

testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.backend.Commit()
Expand All @@ -218,7 +212,7 @@ func TestUnpackDepositLogData_OK(t *testing.T) {
t.Fatalf("Unable to retrieve logs %v", err)
}

_, depositData, index, _, err := contracts.UnpackDepositLogData(logz[0].Data)
_, depositData, index, _, _, err := contracts.UnpackDepositLogData(logz[0].Data)
if err != nil {
t.Fatalf("Unable to unpack logs %v", err)
}
Expand Down Expand Up @@ -287,7 +281,7 @@ func TestProcessChainStartLog_8DuplicatePubkeys(t *testing.T) {
// is 2**14
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

Expand Down Expand Up @@ -372,7 +366,7 @@ func TestProcessChainStartLog_8UniquePubkeys(t *testing.T) {
}

testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

Expand Down Expand Up @@ -455,7 +449,7 @@ func TestUnpackChainStartLogData_OK(t *testing.T) {
// is defined in the deposit contract as the number required for the testnet.
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}

Expand Down Expand Up @@ -530,7 +524,7 @@ func TestHasChainStartLogOccurred_OK(t *testing.T) {
// is defined in the deposit contract as the number required for the testnet.
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.backend.Commit()
Expand Down Expand Up @@ -591,7 +585,7 @@ func TestETH1DataGenesis_OK(t *testing.T) {
// is defined in the deposit contract as the number required for the testnet.
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.backend.Commit()
Expand All @@ -604,14 +598,14 @@ func TestETH1DataGenesis_OK(t *testing.T) {
t.Error("Expected chain start log to have occurred")
}

chainStartIterator, err := testAcc.contract.FilterChainStart(nil)
eth2GenesisIterator, err := testAcc.contract.FilterEth2Genesis(nil)
if err != nil {
t.Fatalf("Could not create chainstart iterator: %v", err)
}

defer chainStartIterator.Close()
chainStartIterator.Next()
chainStartlog := chainStartIterator.Event
defer eth2GenesisIterator.Close()
eth2GenesisIterator.Next()
chainStartlog := eth2GenesisIterator.Event

expectedETH1Data := &pb.Eth1Data{
BlockRoot: chainStartlog.Raw.BlockHash[:],
Expand All @@ -621,7 +615,7 @@ func TestETH1DataGenesis_OK(t *testing.T) {
// We add in another 8 deposits after chainstart.
for i := 0; i < depositsReqForChainStart; i++ {
testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, serializedData.Bytes()); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, data.Pubkey, data.WithdrawalCredentialsHash32, data.ProofOfPossession); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.backend.Commit()
Expand Down
8 changes: 4 additions & 4 deletions beacon-chain/powchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ type Web3Service struct {
depositContractCaller *contracts.DepositContractCaller
depositRoot []byte
depositTrie *trieutil.MerkleTrie
chainStartDeposits [][]byte
chainStartDeposits []*pb.Deposit
chainStarted bool
chainStartETH1Data *pb.Eth1Data
beaconDB *db.BeaconDB
Expand Down Expand Up @@ -127,7 +127,7 @@ func NewWeb3Service(ctx context.Context, config *Web3ServiceConfig) (*Web3Servic
}

ctx, cancel := context.WithCancel(ctx)
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{{}}, int(params.BeaconConfig().DepositContractTreeDepth))
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
if err != nil {
cancel()
return nil, fmt.Errorf("could not setup deposit trie: %v", err)
Expand All @@ -149,7 +149,7 @@ func NewWeb3Service(ctx context.Context, config *Web3ServiceConfig) (*Web3Servic
httpLogger: config.HTTPLogger,
blockFetcher: config.BlockFetcher,
depositContractCaller: depositContractCaller,
chainStartDeposits: [][]byte{},
chainStartDeposits: make([]*pb.Deposit, 0),
beaconDB: config.BeaconDB,
lastReceivedMerkleIndex: -1,
lastRequestedBlock: big.NewInt(0),
Expand Down Expand Up @@ -185,7 +185,7 @@ func (w *Web3Service) ChainStartFeed() *event.Feed {

// ChainStartDeposits returns a slice of validator deposit data processed
// by the deposit contract and cached in the powchain service.
func (w *Web3Service) ChainStartDeposits() [][]byte {
func (w *Web3Service) ChainStartDeposits() []*pb.Deposit {
return w.chainStartDeposits
}

Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/powchain/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func TestInitDataFromContract_OK(t *testing.T) {
}

testAcc.txOpts.Value = amount32Eth
if _, err := testAcc.contract.Deposit(testAcc.txOpts, []byte{'a'}); err != nil {
if _, err := testAcc.contract.Deposit(testAcc.txOpts, []byte{'a'}, []byte{'a'}, []byte{'a'}); err != nil {
t.Fatalf("Could not deposit to deposit contract %v", err)
}
testAcc.backend.Commit()
Expand Down
17 changes: 12 additions & 5 deletions beacon-chain/rpc/beacon_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,18 +258,25 @@ func (bs *BeaconServer) defaultDataResponse(ctx context.Context, currentHeight *
}
// Fetch all historical deposits up to an ancestor height.
allDeposits := bs.beaconDB.AllDeposits(ctx, ancestorHeight)
depositData := [][]byte{}
depositHashes := [][]byte{}
// If there are less than or equal to len(ChainStartDeposits) historical deposits, then we just fetch the default
// deposit root obtained from constructing the Merkle trie with the ChainStart deposits.
chainStartDeposits := bs.powChainService.ChainStartDeposits()
chainStartDeposits, err := bs.powChainService.ChainStartDepositHashes()
if err != nil {
return nil, fmt.Errorf("could not retrieve chainstart deposit hashes %v", err)
}
if len(allDeposits) <= len(chainStartDeposits) {
depositData = chainStartDeposits
depositHashes = chainStartDeposits
} else {
for i := range allDeposits {
depositData = append(depositData, allDeposits[i].DepositData)
hash, err := hashutil.DepositHash(allDeposits[i].Data)
if err != nil {
return nil, err
}
depositHashes = append(depositHashes, hash[:])
}
}
depositTrie, err := trieutil.GenerateTrieFromItems(depositData, int(params.BeaconConfig().DepositContractTreeDepth))
depositTrie, err := trieutil.GenerateTrieFromItems(depositHashes, int(params.BeaconConfig().DepositContractTreeDepth))
if err != nil {
return nil, fmt.Errorf("could not generate historical deposit trie from deposits: %v", err)
}
Expand Down
16 changes: 12 additions & 4 deletions beacon-chain/rpc/beacon_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ func (f *faultyPOWChainService) DepositTrie() *trieutil.MerkleTrie {
return &trieutil.MerkleTrie{}
}

func (f *faultyPOWChainService) ChainStartDeposits() [][]byte {
return [][]byte{}
func (f *faultyPOWChainService) ChainStartDeposits() []*pbp2p.Deposit {
return []*pbp2p.Deposit{}
}

func (f *faultyPOWChainService) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, errors.New("hashing failed")
}

type mockPOWChainService struct {
Expand Down Expand Up @@ -126,8 +130,12 @@ func (m *mockPOWChainService) DepositRoot() [32]byte {
return bytesutil.ToBytes32(root)
}

func (m *mockPOWChainService) ChainStartDeposits() [][]byte {
return [][]byte{}
func (m *mockPOWChainService) ChainStartDeposits() []*pbp2p.Deposit {
return []*pbp2p.Deposit{}
}

func (m *mockPOWChainService) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, nil
}

func TestWaitForChainStart_ContextClosed(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion beacon-chain/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ type powChainService interface {
BlockTimeByHeight(ctx context.Context, height *big.Int) (uint64, error)
DepositRoot() [32]byte
DepositTrie() *trieutil.MerkleTrie
ChainStartDeposits() [][]byte
ChainStartDepositHashes() ([][]byte, error)
ChainStartDeposits() []*pbp2p.Deposit
}

type syncService interface {
Expand Down
Loading