diff --git a/process/receiptslog/errors.go b/process/receiptslog/errors.go index dba0845509..d9d3fa1174 100644 --- a/process/receiptslog/errors.go +++ b/process/receiptslog/errors.go @@ -7,3 +7,6 @@ var ErrNilTrieInteractor = errors.New("trie interactor is nil") // ErrNilReceiptsDataSyncer signals that a nil receipt data syncer has been provided var ErrNilReceiptsDataSyncer = errors.New("receipts data syncer is nil") + +// ErrReceiptTrieRootHashDoesNotMatch signal that the receipts trie root hash does not match +var ErrReceiptTrieRootHashDoesNotMatch = errors.New("receipts trie root hash does not match") diff --git a/process/receiptslog/interface.go b/process/receiptslog/interface.go index 9459c04039..d3295fd496 100644 --- a/process/receiptslog/interface.go +++ b/process/receiptslog/interface.go @@ -14,7 +14,7 @@ type Interactor interface { Save() ([]byte, error) GetSerializedNode(nodeHash []byte) ([]byte, error) RecreateTrieFromDB(rootHash []byte, db storage.Persister) (common.Trie, error) - SaveNewTrie(localTrie common.Trie) error + SaveNewTrie(localTrie common.Trie) ([]byte, error) IsInterfaceNil() bool } diff --git a/process/receiptslog/receiptsManager.go b/process/receiptslog/receiptsManager.go index b850c38b65..38ea4184d3 100644 --- a/process/receiptslog/receiptsManager.go +++ b/process/receiptslog/receiptsManager.go @@ -1,7 +1,10 @@ package receiptslog import ( + "bytes" "context" + "encoding/hex" + "fmt" "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data/state" @@ -38,7 +41,7 @@ func NewReceiptsManager(args ArgsReceiptsManager) (*receiptsManager, error) { if check.IfNil(args.TrieHandler) { return nil, ErrNilTrieInteractor } - if args.ReceiptsDataSyncer == nil { + if check.IfNil(args.ReceiptsDataSyncer) { return nil, ErrNilReceiptsDataSyncer } @@ -98,19 +101,23 @@ func (rm *receiptsManager) SyncReceiptsTrie(receiptsRootHash []byte) error { return err } - return rm.trieInteractor.SaveNewTrie(newTrie) + newTrieRootHash, err := rm.trieInteractor.SaveNewTrie(newTrie) + if err != nil { + return err + } + + if !bytes.Equal(newTrieRootHash, receiptsRootHash) { + return fmt.Errorf("%v , expected=%s, actual=%s", ErrReceiptTrieRootHashDoesNotMatch, hex.EncodeToString(receiptsRootHash), hex.EncodeToString(newTrieRootHash)) + } + + return nil } func (rm *receiptsManager) syncBranchNodesData(receiptsRootHash []byte) (map[string][]byte, error) { - err := rm.receiptsDataSyncer.SyncReceiptsDataFor([][]byte{receiptsRootHash}, context.Background()) - if err != nil { - return nil, err - } - receiptsDataMap, err := rm.receiptsDataSyncer.GetReceiptsData() + receiptsDataMap, err := rm.syncData([][]byte{receiptsRootHash}) if err != nil { return nil, err } - rm.receiptsDataSyncer.ClearFields() receiptTrieBranchNodesBytes := receiptsDataMap[string(receiptsRootHash)] @@ -123,16 +130,22 @@ func (rm *receiptsManager) syncBranchNodesData(receiptsRootHash []byte) (map[str return serializedNodes.SerializedNodes, nil } -func (rm *receiptsManager) syncLeafNodesAndPutInStorer(hashes [][]byte, db storage.Persister) error { +func (rm *receiptsManager) syncData(hashes [][]byte) (map[string][]byte, error) { err := rm.receiptsDataSyncer.SyncReceiptsDataFor(hashes, context.Background()) if err != nil { - return err + return nil, err } - leafNodesMap, err := rm.receiptsDataSyncer.GetReceiptsData() + + defer rm.receiptsDataSyncer.ClearFields() + + return rm.receiptsDataSyncer.GetReceiptsData() +} + +func (rm *receiptsManager) syncLeafNodesAndPutInStorer(hashes [][]byte, db storage.Persister) error { + leafNodesMap, err := rm.syncData(hashes) if err != nil { return err } - rm.receiptsDataSyncer.ClearFields() for leafHash, leafBytes := range leafNodesMap { err = db.Put([]byte(leafHash), leafBytes) diff --git a/process/receiptslog/storageManager.go b/process/receiptslog/storageManager.go index 61926aac05..ffded40665 100644 --- a/process/receiptslog/storageManager.go +++ b/process/receiptslog/storageManager.go @@ -10,6 +10,7 @@ type storageManagerOnlyGet struct { db storage.Persister } +// NewStorageManagerOnlyGet will create a new instance of storageManagerOnlyGet func NewStorageManagerOnlyGet(db storage.Persister) (*storageManagerOnlyGet, error) { return &storageManagerOnlyGet{ db: db, @@ -61,6 +62,7 @@ func (s storageManagerOnlyGet) GetFromCurrentEpoch(_ []byte) ([]byte, error) { return nil, nil } +// PutInEpochWithoutCache - func (s storageManagerOnlyGet) PutInEpochWithoutCache(_ []byte, _ []byte, _ uint32) error { return nil } @@ -97,6 +99,7 @@ func (s storageManagerOnlyGet) RemoveFromAllActiveEpochs(_ []byte) error { return nil } +// SetEpochForPutOperation - func (s storageManagerOnlyGet) SetEpochForPutOperation(_ uint32) { } diff --git a/process/receiptslog/trieInteractor.go b/process/receiptslog/trieInteractor.go index 672abcf7f3..2e2af473c0 100644 --- a/process/receiptslog/trieInteractor.go +++ b/process/receiptslog/trieInteractor.go @@ -6,6 +6,7 @@ import ( "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-go/common" + "github.com/multiversx/mx-chain-go/common/holders" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/storage" @@ -65,12 +66,10 @@ func (ti *trieInteractor) CreateNewTrie() error { } // SaveNewTrie will save in storage the synced trie -func (ti *trieInteractor) SaveNewTrie(localTrie common.Trie) error { +func (ti *trieInteractor) SaveNewTrie(localTrie common.Trie) ([]byte, error) { ti.localTrie = localTrie - _, err := ti.Save() - - return err + return ti.Save() } // AddReceiptData will add receipt data in local trie @@ -152,11 +151,6 @@ func (ti *trieInteractor) saveReceiptTxHashLeafKey(leafHash []byte, leafData []b return ti.storage.Put(receiptData.TxHash, leafHash) } -// IsInterfaceNil returns true if there is no value under the interface -func (ti *trieInteractor) IsInterfaceNil() bool { - return ti == nil -} - func checkArgs(args ArgsTrieInteractor) error { if check.IfNil(args.EnableEpochsHandler) { return process.ErrNilEnableEpochsHandler @@ -174,6 +168,22 @@ func checkArgs(args ArgsTrieInteractor) error { return nil } +// RecreateTrieFromDB will recreate the trie from the provided storer +func (ti *trieInteractor) RecreateTrieFromDB(rootHash []byte, db storage.Persister) (common.Trie, error) { + storageManager, err := NewStorageManagerOnlyGet(db) + if err != nil { + return nil, err + } + + localTrie, err := trie.NewTrie(storageManager, ti.marshaller, ti.hasher, ti.enableEpochsHandler, maxTrieLevelInMemory) + if err != nil { + return nil, err + } + + rootHashHolder := holders.NewDefaultRootHashesHolder(rootHash) + return localTrie.Recreate(rootHashHolder) +} + func (ti *trieInteractor) saveNodeData(currentNodeData *trie.CurrentNodeInfo, serializedNodes *state.SerializedNodeMap) error { if currentNodeData.Type != trie.LeafNodeType { serializedNodes.SerializedNodes[string(currentNodeData.Hash)] = currentNodeData.SerializedNode @@ -187,3 +197,8 @@ func (ti *trieInteractor) saveNodeData(currentNodeData *trie.CurrentNodeInfo, se return ti.saveReceiptTxHashLeafKey(currentNodeData.Hash, currentNodeData.Value) } + +// IsInterfaceNil returns true if there is no value under the interface +func (ti *trieInteractor) IsInterfaceNil() bool { + return ti == nil +} diff --git a/process/receiptslog/trieRecreate.go b/process/receiptslog/trieRecreate.go deleted file mode 100644 index 6a1fb5b400..0000000000 --- a/process/receiptslog/trieRecreate.go +++ /dev/null @@ -1,24 +0,0 @@ -package receiptslog - -import ( - "github.com/multiversx/mx-chain-go/common" - "github.com/multiversx/mx-chain-go/common/holders" - "github.com/multiversx/mx-chain-go/storage" - "github.com/multiversx/mx-chain-go/trie" -) - -// RecreateTrieFromDB will recreate the trie from the provided storer -func (ti *trieInteractor) RecreateTrieFromDB(rootHash []byte, db storage.Persister) (common.Trie, error) { - storageManager, err := NewStorageManagerOnlyGet(db) - if err != nil { - return nil, err - } - - localTrie, err := trie.NewTrie(storageManager, ti.marshaller, ti.hasher, ti.enableEpochsHandler, maxTrieLevelInMemory) - if err != nil { - return nil, err - } - - rootHashHolder := holders.NewDefaultRootHashesHolder(rootHash) - return localTrie.Recreate(rootHashHolder) -} diff --git a/testscommon/receiptsDataSyncerStub.go b/testscommon/receiptsDataSyncerStub.go index 030ee38fe6..9c3476bdea 100644 --- a/testscommon/receiptsDataSyncerStub.go +++ b/testscommon/receiptsDataSyncerStub.go @@ -2,6 +2,7 @@ package testscommon import "context" +// ReceiptsDataSyncerStub - type ReceiptsDataSyncerStub struct { GetReceiptsDataCalled func() (map[string][]byte, error) SyncReceiptsDataForCalled func(hashes [][]byte, ctx context.Context) error diff --git a/trie/receiptsTrie.go b/trie/receiptsTrie.go index 62bf51f6d4..fd1bf2587a 100644 --- a/trie/receiptsTrie.go +++ b/trie/receiptsTrie.go @@ -1,8 +1,6 @@ package trie import ( - "fmt" - "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-go/storage" @@ -22,14 +20,12 @@ func GetLeafHashesAndPutNodesInRamStorage( return nil, err } - hashes := decodedNode.getChildrenHashes() - if len(hashes) == 0 { + childrenHashes := decodedNode.getChildrenHashes() + if len(childrenHashes) == 0 { continue } - leafHashes = append(leafHashes, hashes...) - - fmt.Println("here", len(nodeHash), len([]byte(nodeHash))) + leafHashes = append(leafHashes, getLeafHashesFromChildrenHashes(childrenHashes, branchNodesMap)...) err = db.Put([]byte(nodeHash), branchNodeSerialized) if err != nil { @@ -39,3 +35,17 @@ func GetLeafHashesAndPutNodesInRamStorage( return leafHashes, nil } + +func getLeafHashesFromChildrenHashes(childrenHashes [][]byte, nodesMap map[string][]byte) [][]byte { + leafHashes := make([][]byte, 0) + for _, childHash := range childrenHashes { + _, isBranchNodeOrExtensionNode := nodesMap[string(childHash)] + if isBranchNodeOrExtensionNode { + continue + } + + leafHashes = append(leafHashes, childHash) + } + + return leafHashes +}