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

Initial MPT implementation (2.x) #990

Merged
merged 5 commits into from
Jun 1, 2020
Merged

Initial MPT implementation (2.x) #990

merged 5 commits into from
Jun 1, 2020

Conversation

fyrchik
Copy link
Contributor

@fyrchik fyrchik commented May 27, 2020

This is initial MPT implementation, containing most of the necessary methods.
Storage key transformation to NEO format will be done during integration.

@codecov
Copy link

codecov bot commented May 27, 2020

Codecov Report

Merging #990 into neox-2.x will increase coverage by 0.97%.
The diff coverage is 94.80%.

Impacted file tree graph

@@             Coverage Diff              @@
##           neox-2.x     #990      +/-   ##
============================================
+ Coverage     67.97%   68.94%   +0.97%     
============================================
  Files           145      153       +8     
  Lines         14320    14859     +539     
============================================
+ Hits           9734    10245     +511     
- Misses         4126     4143      +17     
- Partials        460      471      +11     
Impacted Files Coverage Δ
pkg/core/storage/store.go 34.61% <ø> (ø)
pkg/core/mpt/hash.go 83.78% <83.78%> (ø)
pkg/core/mpt/branch.go 89.47% <89.47%> (ø)
pkg/core/mpt/trie.go 93.24% <93.24%> (ø)
pkg/core/mpt/leaf.go 96.42% <96.42%> (ø)
pkg/core/mpt/extension.go 97.43% <97.43%> (ø)
pkg/core/mpt/helpers.go 100.00% <100.00%> (ø)
pkg/core/mpt/node.go 100.00% <100.00%> (ø)
pkg/core/mpt/proof.go 100.00% <100.00%> (ø)
... and 7 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7a783b6...314430b. Read the comment docs.

Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

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

We absolutely need some tests that compare root hashes with ones from C# implementation (there are some UTs there that have samples of these)


// toBytes is a helper for serializing node.
func toBytes(n Node) []byte {
buf := io.NewBufBinWriter()
Copy link
Member

Choose a reason for hiding this comment

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

It should be OK for a start, but this probably will be allocating like crazy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes and we can't use a single buffer, because this conversion is performed recursively, e.g. on Branch nodes. I decided not to use any kind of pools it for now, to keep this simple.

Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

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

I think I'm done with the first four (for #964) and they're fine in general, just some minor tweaks are needed. I'll take a look at the rest of them a bit later (for #998, #1004, #1005). Maybe we'll also merge them separately (depends on their state of course).

}

b := NewBranchNode()
r, err := t.putWithPath(b.Children[path[0]], path[1:], v)
Copy link
Member

Choose a reason for hiding this comment

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

You're a bit inconsistent here, putBranch uses splitPath in similar situation and given that you're using path[0] down below again, probably it's better to do so here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's because we compare length of the path with 0 earlier.

}

// VerifyProof verifies that path indeed belongs to a MPT with the specified root hash.
func VerifyProof(rh util.Uint256, path []byte, proofs [][]byte) ([]byte, bool) {
Copy link
Member

Choose a reason for hiding this comment

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

It's an external interface, it should accept simple path and convert it to nibbles. BTW, that's the way VerifyProof() in C# works.

Copy link
Member

Choose a reason for hiding this comment

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

To be fair, I don't really like its interface with []byte returned, but maybe it's ok for now. I expect a verification of KV pair, at the moment it looks more like a GetVerifiedContentForTheKey. But probably it's not a problem as of yet.

@@ -74,6 +90,38 @@ func TestNode_Serializable(t *testing.T) {
})
}

func TestInvalidJSON(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

Encoding/decoding and invalid JSON tests are all nice, but we also need some known-good JSON strings to decode. The ones generated by encoding are not appropriate as we need to follow a specific encoding standard set by C# implementation and internal enc/dec doesn't prove we're compliant with that.

Copy link
Member

Choose a reason for hiding this comment

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

Are there any that can be taken from C# tests or generated by the respective node?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@roman-khimov
Copy link
Member

roman-khimov commented May 31, 2020 via email

@roman-khimov
Copy link
Member

roman-khimov commented May 31, 2020 via email

Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

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

Things obviously missing:

  • key grouping
  • p2p processing

I think we can concentrate here on base MPT structure and merge p2p/storage/consensus changes in other PRs.

@@ -86,7 +90,9 @@ func (dao *Simple) GetBatch() *storage.MemBatch {
// GetWrapped returns new DAO instance with another layer of wrapped
// MemCachedStore around the current DAO Store.
func (dao *Simple) GetWrapped() DAO {
return NewSimple(dao.Store)
d := NewSimple(dao.Store)
d.MPT = dao.MPT
Copy link
Member

Choose a reason for hiding this comment

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

An interesting part is that this should work for Cached because of its storage item cache. Though it probably won't for the master branch.

@@ -507,6 +508,8 @@ func (s *Server) handleGetDataCmd(p Peer, inv *payload.Inventory) error {
if err == nil {
msg = s.MkMsg(CMDBlock, b)
}
case payload.StateRootType:
return nil // TODO
Copy link
Member

Choose a reason for hiding this comment

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

Not there yet.

fyrchik added 5 commits June 1, 2020 18:14
MPT is a trie with a branching factor = 16, i.e. it consists of sequences in
16-element alphabet.
Because there is no distinct type field in JSONized nodes, distinction
is made via payload itself, thus all unmarshaling is done via
NodeObject.
Because trie size is rather big, it can't be stored in memory.
Thus some form of caching should also be implemented. To avoid
marshaling/unmarshaling of items which are close to root and are used
very frequenly we can save them across the persists.
This commit implements pruning items at the specified depth,
replacing them by hash nodes.
@roman-khimov roman-khimov merged commit 2f90a06 into neox-2.x Jun 1, 2020
@roman-khimov roman-khimov deleted the feature/mpt branch June 1, 2020 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Completely new functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants