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

Track Previously Seen Merkle Index to Prevent Duplicate Log Spam #1566

Merged
merged 40 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
86fcda2
using little endian and tests for encoding dep inputs
Feb 8, 2019
c74307c
use decode value and timestamp method in state
Feb 8, 2019
19f3686
updated comments to match serialization format
Feb 8, 2019
1927a41
latest compiled contract, abi, bytecode, and bindings
Feb 10, 2019
4a74367
resolve some conflicts
Feb 10, 2019
92410cb
to little endian everywhere
Feb 10, 2019
f60565b
fix all tests except for contract tests
Feb 10, 2019
156705c
Merge branch 'new-contract' into fix-encoding-decoding
Feb 10, 2019
df64ad9
include contract changes
Feb 10, 2019
5d81cba
Merge branch 'master' into fix-encoding-decoding
rauljordan Feb 10, 2019
21a3a9d
Merge branch 'master' into fix-encoding-decoding
terencechain Feb 10, 2019
dee0a28
address broken build
Feb 10, 2019
cbc8066
Merge branch 'master' into fix-encoding-decoding
rauljordan Feb 11, 2019
da6a588
compile with vyper v8
Feb 11, 2019
5522e79
update readme
Feb 11, 2019
b35fddf
merge master
Feb 11, 2019
2949353
Merge branch 'master' into fix-encoding-decoding
rauljordan Feb 11, 2019
f319e02
fix pkg name
Feb 11, 2019
0f9f0e2
add skip chainstart delay
Feb 11, 2019
b0cf284
skip chainstart delay tests pass
Feb 11, 2019
07af614
Merge branch 'master' into fix-encoding-decoding
rauljordan Feb 11, 2019
95513e5
to little endian timestamp
Feb 11, 2019
7848df0
Merge branch 'fix-encoding-decoding' of github.com:prysmaticlabs/prys…
Feb 11, 2019
eae8948
pull origin
Feb 11, 2019
416c1de
using genesis timestamp instead of bool
Feb 11, 2019
bb7f5cd
update with gofmt
Feb 11, 2019
c61424a
Merge branch 'master' into no-merkle-prestart
rauljordan Feb 12, 2019
b036fca
make more fields public
Feb 12, 2019
6250120
resolve with master
Feb 12, 2019
9e2a1ad
Merge branch 'no-merkle-prestart' into track-prev-index
Feb 12, 2019
b014659
duplicate log spam inconsistent root fixed by tracking last seen index
Feb 12, 2019
93519db
resolve confs with master
Feb 12, 2019
6686957
sync with master
Feb 12, 2019
c0d6569
readd weird removal of import
Feb 12, 2019
bf5d95b
readd libp2p import
Feb 12, 2019
4cbe966
gazelle
Feb 12, 2019
1646ae7
readd eth
Feb 12, 2019
574e8bb
Merge branch 'master' into track-prev-index
rauljordan Feb 12, 2019
6852d47
comments
Feb 12, 2019
664a926
Merge branch 'track-prev-index' of github.com:prysmaticlabs/prysm int…
Feb 12, 2019
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
82 changes: 46 additions & 36 deletions beacon-chain/powchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"strings"
"time"

"github.com/ethereum/go-ethereum"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -70,24 +70,25 @@ type Client interface {
// Validator Registration Contract on the ETH1.0 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
depositContractAddress common.Address
chainStartFeed *event.Feed
reader Reader
logger bind.ContractFilterer
blockNumber *big.Int // the latest ETH1.0 chain blockNumber.
blockHash common.Hash // the latest ETH1.0 chain blockHash.
depositContractCaller *contracts.DepositContractCaller
depositRoot []byte
depositTrie *trieutil.DepositTrie
chainStartDeposits []*pb.Deposit
chainStarted bool
beaconDB *db.BeaconDB
ctx context.Context
cancel context.CancelFunc
client Client
headerChan chan *gethTypes.Header
logChan chan gethTypes.Log
endpoint string
depositContractAddress common.Address
chainStartFeed *event.Feed
reader Reader
logger bind.ContractFilterer
blockNumber *big.Int // the latest ETH1.0 chain blockNumber.
blockHash common.Hash // the latest ETH1.0 chain blockHash.
depositContractCaller *contracts.DepositContractCaller
depositRoot []byte
depositTrie *trieutil.DepositTrie
chainStartDeposits []*pb.Deposit
chainStarted bool
beaconDB *db.BeaconDB
lastReceivedMerkleIndex int64 // Keeps track of the last received index to prevent log spam.
}

// Web3ServiceConfig defines a config struct for web3 service to use through its life cycle.
Expand Down Expand Up @@ -123,21 +124,22 @@ func NewWeb3Service(ctx context.Context, config *Web3ServiceConfig) (*Web3Servic

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{}),
depositContractAddress: config.DepositContract,
chainStartFeed: new(event.Feed),
client: config.Client,
reader: config.Reader,
logger: config.Logger,
depositContractCaller: depositContractCaller,
chainStartDeposits: []*pb.Deposit{},
beaconDB: config.BeaconDB,
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,
chainStartFeed: new(event.Feed),
client: config.Client,
reader: config.Reader,
logger: config.Logger,
depositContractCaller: depositContractCaller,
chainStartDeposits: []*pb.Deposit{},
beaconDB: config.BeaconDB,
lastReceivedMerkleIndex: -1,
}, nil
}

Expand Down Expand Up @@ -227,15 +229,24 @@ func (w *Web3Service) ProcessLog(VRClog gethTypes.Log) {
// the ETH1.0 chain by trying to ascertain which participant deposited
// in the contract.
func (w *Web3Service) ProcessDepositLog(VRClog gethTypes.Log) {
merkleRoot, depositData, MerkleTreeIndex, _, err := contracts.UnpackDepositLogData(VRClog.Data)
merkleRoot, depositData, merkleTreeIndex, _, err := contracts.UnpackDepositLogData(VRClog.Data)
if err != nil {
log.Errorf("Could not unpack log %v", err)
return
}
// If we have already seen this Merkle index, skip processing the log.
// This can happen sometimes when we receive the same log twice from the
// ETH1.0 network, and prevents us from updating our trie
// with the same log twice, causing an inconsistent state root.
index := binary.LittleEndian.Uint64(merkleTreeIndex)
if int64(index) == w.lastReceivedMerkleIndex {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be

if int64(index) <= w.lastReceivedMerkleIndex {

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch

return
}
if err := w.saveInTrie(depositData, merkleRoot); err != nil {
log.Errorf("Could not save in trie %v", err)
return
}
w.lastReceivedMerkleIndex = int64(index)
depositInput, err := blocks.DecodeDepositInput(depositData)
if err != nil {
log.Errorf("Could not decode deposit input %v", err)
Expand All @@ -250,7 +261,6 @@ func (w *Web3Service) ProcessDepositLog(VRClog gethTypes.Log) {
} else {
w.beaconDB.InsertPendingDeposit(w.ctx, deposit, big.NewInt(int64(VRClog.BlockNumber)))
}
index := binary.LittleEndian.Uint64(MerkleTreeIndex)
log.WithFields(logrus.Fields{
"publicKey": fmt.Sprintf("%#x", depositInput.Pubkey),
"merkleTreeIndex": index,
Expand Down
67 changes: 66 additions & 1 deletion beacon-chain/powchain/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum"
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"
Expand Down Expand Up @@ -533,6 +533,71 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
}
}

func TestProcessDepositLog_SkipDuplicateLog(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,
BeaconDB: &db.BeaconDB{},
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/unable/Unable

}

testAcc.backend.Commit()

web3Service.depositTrie = trieutil.NewDepositTrie()

var stub [48]byte
copy(stub[:], []byte("testing"))

data := &pb.DepositInput{
Pubkey: stub[:],
ProofOfPossession: stub[:],
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 {
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)
}

web3Service.ProcessDepositLog(logs[0])
// We keep track of the current deposit root and make sure it doesn't change if we
// receive a duplicate log from the contract.
currentRoot := web3Service.depositTrie.Root()
web3Service.ProcessDepositLog(logs[0])
nextRoot := web3Service.depositTrie.Root()
if currentRoot != nextRoot {
t.Error("Processing a duplicate log should not update deposit trie")
}
}

func TestUnpackDepositLogs(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
Expand Down
2 changes: 1 addition & 1 deletion shared/keystore/keystore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"testing"

"github.com/pborman/uuid"
"github.com/prysmaticlabs/go-bls"
bls "github.com/prysmaticlabs/go-bls"
)

func TestStoreandGetKey(t *testing.T) {
Expand Down