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

Optimize Insertion in Deposit Trie #4299

Merged
merged 21 commits into from
Dec 17, 2019
Merged

Conversation

nisdas
Copy link
Member

@nisdas nisdas commented Dec 16, 2019

Resolves #[PR]


Background

Our current workflow for computing the Merkle trie of eth1 deposits is as follows:

  • Keep track of all deposits we have seen
  • As soon as a new deposit comes in, recompute the entire Merkle trie of deposits from its leaves

This means every new deposit takes up O(n) in runtime, which makes it difficult to process a large number of deposit logs. This PR brings insertion down to O(log n), as instead we can just recompute the changed branch when a new deposit is seen. This will be a huge improvement to the initial deposit verification flow upon launching the beacon node.

Benchmark Results

goos: darwin
goarch: amd64
BenchmarkInsertTrie_Optimized-4            61989             16087 ns/op
BenchmarkInsertTrie_Slow-4                   111          10635884 ns/op
PASS

@rauljordan rauljordan marked this pull request as ready for review December 16, 2019 21:37
enc := [32]byte{}
binary.LittleEndian.PutUint64(enc[:], uint64(len(m.originalItems)))
return hashutil.Hash(append(m.branches[len(m.branches)-1][0], enc[:]...))
}

// InsertIntoTrie inserts an item(deposit hash) into the trie.
func (m *SparseMerkleTrie) InsertIntoTrie(item []byte, index int) {
for index >= len(m.branches[0]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Given this is a sparse merkle trie, sometimes we may be attempting to insert something at index 15 when only 5 original leaves exist in the trie, so we have to expand it on-demand

shared/trieutil/sparse_merkle.go Outdated Show resolved Hide resolved
}
parentIdx := currentIndex / 2
// Update the cached layers at the parent index.
if len(m.branches[i+1]) == 0 || parentIdx >= len(m.branches[i+1]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We need some special handling here since the trie is sparse and there may not be an actual object at the index we're trying to modify

@codecov
Copy link

codecov bot commented Dec 16, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@23a6c20). Click here to learn what that means.
The diff coverage is 98.33%.

@@            Coverage Diff            @@
##             master    #4299   +/-   ##
=========================================
  Coverage          ?   35.68%           
=========================================
  Files             ?        9           
  Lines             ?      524           
  Branches          ?        0           
=========================================
  Hits              ?      187           
  Misses            ?      332           
  Partials          ?        5

Copy link
Member

@terencechain terencechain left a comment

Choose a reason for hiding this comment

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

go imports and a naming feedback

contracts/deposit-contract/deposit_tree_test.go Outdated Show resolved Hide resolved
enc := [32]byte{}
binary.LittleEndian.PutUint64(enc[:], uint64(len(m.originalItems)))
return hashutil.Hash(append(m.branches[len(m.branches)-1][0], enc[:]...))
}

// InsertIntoTrie inserts an item(deposit hash) into the trie.
func (m *SparseMerkleTrie) InsertIntoTrie(item []byte, index int) {
Copy link
Member

Choose a reason for hiding this comment

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

Would Insert be more clear? Given the receiver is already SparseMerkleTrie

@@ -43,7 +44,7 @@ func TestDepositTrieRoot_OK(t *testing.T) {

testAcc.TxOpts.Value = depositcontract.Amount32Eth()

for i := 0; i < 100; i++ {
for i := 0; i < 5; i++ {
Copy link
Member

Choose a reason for hiding this comment

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

Why lower this?

@@ -32,7 +33,7 @@ func TestDepositTrieRoot_OK(t *testing.T) {
t.Errorf("Local deposit trie root and contract deposit trie root are not equal. Expected %#x , Got %#x", depRoot, localTrie.Root())
}

privKeys, pubKeys, err := interop.DeterministicallyGenerateKeys(0 /*startIndex*/, 101)
privKeys, pubKeys, err := interop.DeterministicallyGenerateKeys(0 /*startIndex*/, 10)
Copy link
Member

Choose a reason for hiding this comment

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

Why?

@@ -6,6 +6,7 @@ import (

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/prysmaticlabs/go-ssz"

Copy link
Member

Choose a reason for hiding this comment

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

Revert new line please

@rauljordan rauljordan added the Ready For Review A pull request ready for code review label Dec 16, 2019
terencechain
terencechain previously approved these changes Dec 17, 2019
@prylabs-bulldozer prylabs-bulldozer bot merged commit c41140e into master Dec 17, 2019
@delete-merged-branch delete-merged-branch bot deleted the optimizeDepositLogs branch December 17, 2019 02:19
cryptomental pushed a commit to cryptomental/prysm that referenced this pull request Feb 24, 2020
* current changes
* change algorithm for tree insert
* almost done with getting this to pass
* unit test passes
* tests now pass
* fix in repo
* Merge branch 'master' into optimizeDepositLogs
* fix build
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* remove tautology
* fix tautology
* fix up sparsity
* Merge branch 'master' into optimizeDepositLogs
* further fixes
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* Update shared/trieutil/sparse_merkle.go
* comments
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* add bench for optimized
* gaz
* Merge refs/heads/master into optimizeDepositLogs
cryptomental pushed a commit to cryptomental/prysm that referenced this pull request Feb 28, 2020
* current changes
* change algorithm for tree insert
* almost done with getting this to pass
* unit test passes
* tests now pass
* fix in repo
* Merge branch 'master' into optimizeDepositLogs
* fix build
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* remove tautology
* fix tautology
* fix up sparsity
* Merge branch 'master' into optimizeDepositLogs
* further fixes
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* Update shared/trieutil/sparse_merkle.go
* comments
* Merge branch 'optimizeDepositLogs' of github.com:prysmaticlabs/prysm into optimizeDepositLogs
* add bench for optimized
* gaz
* Merge refs/heads/master into optimizeDepositLogs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ready For Review A pull request ready for code review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants