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

trie: make stacktrie not mutate input values #22673

Merged
merged 2 commits into from
Apr 16, 2021

Conversation

holiman
Copy link
Contributor

@holiman holiman commented Apr 15, 2021

The stacktrie is a bit un-untuitive, API-wise: it mutates input values.

This is dangerous, and easy to get wrong if the calling code 'forgets' this quirk, so this PR fixes that behaviour. The first commit provides a testcase, and the second commit provides a fix. Naturally, the fix has an overhead.

With this PR:

name                       old time/op    new time/op    delta
DeriveSha200/std_trie-6       715µs ±13%     722µs ± 7%     ~     (p=0.841 n=5+5)
DeriveSha200/stack_trie-6     453µs ±13%     449µs ± 2%     ~     (p=0.690 n=5+5)

name                       old alloc/op   new alloc/op   delta
DeriveSha200/std_trie-6       273kB ± 0%     273kB ± 0%     ~     (p=0.548 n=5+5)
DeriveSha200/stack_trie-6    52.5kB ± 0%    58.5kB ± 0%  +11.24%  (p=0.016 n=4+5)

name                       old allocs/op  new allocs/op  delta
DeriveSha200/std_trie-6       2.66k ± 0%     2.66k ± 0%     ~     (all equal)
DeriveSha200/stack_trie-6     1.07k ± 0%     1.25k ± 0%  +17.20%  (p=0.008 n=5+5)

Alternative fix:

index a198eb204b..6ba309cb41 100644
--- a/trie/stacktrie.go
+++ b/trie/stacktrie.go
@@ -99,7 +99,7 @@ func (st *StackTrie) TryUpdate(key, value []byte) error {
 	if len(value) == 0 {
 		panic("deletion not supported")
 	}
-	st.insert(k[:len(k)-1], value)
+	st.insert(k[:len(k)-1], common.CopyBytes(value))
 	return nil
 }

With alternative fix:

name                       old time/op    new time/op    delta
DeriveSha200/std_trie-6       715µs ±13%     715µs ± 8%     ~     (p=1.000 n=5+5)
DeriveSha200/stack_trie-6     453µs ±13%     469µs ± 8%     ~     (p=0.310 n=5+5)

name                       old alloc/op   new alloc/op   delta
DeriveSha200/std_trie-6       273kB ± 0%     273kB ± 0%     ~     (p=0.690 n=5+5)
DeriveSha200/stack_trie-6    52.5kB ± 0%    75.0kB ± 0%  +42.77%  (p=0.016 n=4+5)

name                       old allocs/op  new allocs/op  delta
DeriveSha200/std_trie-6       2.66k ± 0%     2.66k ± 0%     ~     (all equal)
DeriveSha200/stack_trie-6     1.07k ± 0%     1.27k ± 0%  +18.69%  (p=0.008 n=5+5)

With this PR in, though, we can make some other improvements to not always copy data on input. However, it should be noted that the stacktrie still needs the caller to not mutate the data from the outside, so we cannot remove e.g. example https://github.com/ethereum/go-ethereum/blob/master/core/types/hashing.go#L80:L83 (btw -- the ordinary trie behaves the same way, you're not allowed to mutate input values from the callsite)

func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte {
	buf.Reset()
	list.EncodeIndex(i, buf)
	// It's really unfortunate that we need to do perform this copy.
	// StackTrie holds onto the values until Hash is called, so the values
	// written to it must not alias.
	return common.CopyBytes(buf.Bytes())
}

@holiman holiman requested a review from gballet April 15, 2021 20:34
Copy link
Member

@gballet gballet left a comment

Choose a reason for hiding this comment

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

LGTM. A bit sad about the stiff increase in allocation numbers, but this way the API is safer.

@holiman holiman added this to the 1.10.3 milestone Apr 16, 2021
@holiman holiman merged commit 4f3ba67 into ethereum:master Apr 16, 2021
atif-konasl pushed a commit to frozeman/pandora-execution-engine that referenced this pull request Oct 15, 2021
The stacktrie is a bit un-untuitive, API-wise: since it mutates input values.
Such behaviour is dangerous, and easy to get wrong if the calling code 'forgets' this quirk. The behaviour is fixed by this PR, so that the input values are not modified by the stacktrie. 

Note: just as with the Trie, the stacktrie still references the live input objects, so it's still _not_ safe to mutate the values form the callsite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants