Skip to content

Commit

Permalink
Merge pull request #6450 from multiversx/receipts-data-trie
Browse files Browse the repository at this point in the history
[lite-client] receipt data trie
  • Loading branch information
AdoAdoAdo authored Sep 25, 2024
2 parents 946d912 + fe6ceed commit b482370
Show file tree
Hide file tree
Showing 13 changed files with 526 additions and 0 deletions.
6 changes: 6 additions & 0 deletions process/receiptslog/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package receiptslog

import "errors"

// ErrNilTrieInteractor signals that a nil trie interactor has been provided
var ErrNilTrieInteractor = errors.New("trie interactor is nil")
18 changes: 18 additions & 0 deletions process/receiptslog/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package receiptslog

import "github.com/multiversx/mx-chain-core-go/data/state"

// Interactor defines what a trie interactor should be able to do
type Interactor interface {
CreateNewTrie() error
AddReceiptData(receiptData state.Receipt) error
Save() ([]byte, error)
IsInterfaceNil() bool
}

// ReceiptsManagerHandler defines what a receipts manager should be able to do
type ReceiptsManagerHandler interface {
GenerateReceiptsTrieAndSaveDataInStorage(args ArgsGenerateReceiptsAndSave) ([]byte, error)
SyncReceiptsTrie(receiptsRootHash []byte) error
IsInterfaceNil() bool
}
67 changes: 67 additions & 0 deletions process/receiptslog/receiptsManager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package receiptslog

import (
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data/state"
)

// ArgsReceiptsManager is the structure that holds the components needed to a new receipts manager
type ArgsReceiptsManager struct {
TrieHandler Interactor
}

// ArgsGenerateReceiptsAndSave is the DTO needed to provided input data to generate receipts
type ArgsGenerateReceiptsAndSave struct {
// add data needed to create receipt structure
// logs
}

type receiptsManager struct {
trieInteractor Interactor
}

// NewReceiptsManager will create a new instance of receipts manager
func NewReceiptsManager(args ArgsReceiptsManager) (*receiptsManager, error) {
if check.IfNil(args.TrieHandler) {
return nil, ErrNilTrieInteractor
}

return &receiptsManager{
trieInteractor: args.TrieHandler,
}, nil
}

// GenerateReceiptsTrieAndSaveDataInStorage will generate the receipts trie based on the input data and return the receipt trie root hash
func (rm *receiptsManager) GenerateReceiptsTrieAndSaveDataInStorage(args ArgsGenerateReceiptsAndSave) ([]byte, error) {
// TODO generate the list of receipts

err := rm.trieInteractor.CreateNewTrie()
if err != nil {
return nil, err
}

receipts := make([]state.Receipt, 0)
for _, rec := range receipts {
err = rm.trieInteractor.AddReceiptData(rec)
if err != nil {
return nil, err
}
}

receiptsRootHash, err := rm.trieInteractor.Save()
if err != nil {
return nil, err
}

return receiptsRootHash, nil
}

// SyncReceiptsTrie will sync the receipts trie from network
func (rm *receiptsManager) SyncReceiptsTrie(receiptsRootHash []byte) error {
return nil
}

// IsInterfaceNil returns true if there is no value under the interface
func (rm *receiptsManager) IsInterfaceNil() bool {
return rm == nil
}
35 changes: 35 additions & 0 deletions process/receiptslog/receiptsManagerCreator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package receiptslog

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/process"
"github.com/multiversx/mx-chain-go/storage"
)

// ArgsCreateReceiptsManager holds all the components needed to create a receipts manager
type ArgsCreateReceiptsManager struct {
ReceiptDataStorer storage.Storer
Marshaller marshal.Marshalizer
Hasher hashing.Hasher
EnableEpochsHandler common.EnableEpochsHandler
RequestHandler process.RequestHandler
}

// CreateReceiptsManager will create a new instance of receipts manager
func CreateReceiptsManager(args ArgsCreateReceiptsManager) (*receiptsManager, error) {
trieHandler, err := NewTrieInteractor(ArgsTrieInteractor{
ReceiptDataStorer: args.ReceiptDataStorer,
Marshaller: args.Marshaller,
Hasher: args.Hasher,
EnableEpochsHandler: args.EnableEpochsHandler,
})
if err != nil {
return nil, err
}

return NewReceiptsManager(ArgsReceiptsManager{
TrieHandler: trieHandler,
})
}
177 changes: 177 additions & 0 deletions process/receiptslog/trieInteractor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package receiptslog

import (
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data/state"
"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/dataRetriever"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/storage"
"github.com/multiversx/mx-chain-go/testscommon/storageManager"
"github.com/multiversx/mx-chain-go/trie"
)

const maxTrieLevelInMemory = 5

// ArgsTrieInteractor is the structure that holds the components needed to a new trie interactor
type ArgsTrieInteractor struct {
ReceiptDataStorer storage.Storer
Marshaller marshal.Marshalizer
Hasher hashing.Hasher
EnableEpochsHandler common.EnableEpochsHandler
}

type trieInteractor struct {
marshaller marshal.Marshalizer
hasher hashing.Hasher
enableEpochsHandler common.EnableEpochsHandler
storage storage.Storer

localTrie common.Trie
}

// NewTrieInteractor will create a new instance of trie interactor
func NewTrieInteractor(args ArgsTrieInteractor) (*trieInteractor, error) {
err := checkArgs(args)
if err != nil {
return nil, err
}

return &trieInteractor{
marshaller: args.Marshaller,
hasher: args.Hasher,
enableEpochsHandler: args.EnableEpochsHandler,
storage: args.ReceiptDataStorer,
}, nil
}

// CreateNewTrie will create a new local trie(also will overwrite the old local trie)
func (ti *trieInteractor) CreateNewTrie() error {
disabledStorageManager := &storageManager.StorageManagerStub{}

localTrie, err := trie.NewTrie(disabledStorageManager, ti.marshaller, ti.hasher, ti.enableEpochsHandler, maxTrieLevelInMemory)
if err != nil {
return err
}

ti.localTrie = localTrie

return nil
}

// AddReceiptData will add receipt data in local trie
func (ti *trieInteractor) AddReceiptData(receiptData state.Receipt) error {
receiptDataBytes, err := ti.marshaller.Marshal(receiptData)
if err != nil {
return err
}

return ti.localTrie.Update(receiptData.TxHash, receiptDataBytes)
}

// Save will save all data from trie in storage and return the receipts root hash
func (ti *trieInteractor) Save() ([]byte, error) {
dfsIterator, err := trie.NewDFSIterator(ti.localTrie)
if err != nil {
return nil, err
}

currentNodeData, errGet := dfsIterator.GetCurrentNodeInfo()
if errGet != nil {
return nil, errGet
}

serializedNodes := make([][]byte, 0)
serializedNodes, err = ti.saveNodeData(currentNodeData, serializedNodes)
if err != nil {
return nil, err
}

for dfsIterator.HasNext() {
err = dfsIterator.Next()
if err != nil {
return nil, err
}

currentNodeData, errGet = dfsIterator.GetCurrentNodeInfo()
if errGet != nil {
return nil, errGet
}

serializedNodes, err = ti.saveNodeData(currentNodeData, serializedNodes)
if err != nil {
return nil, err
}

}

listOfSerializedNodesBytes, err := ti.marshaller.Marshal(&serializedNodes)
if err != nil {
return nil, err
}

receiptTrieRootHash, err := ti.localTrie.RootHash()
if err != nil {
return nil, err
}

err = ti.storage.Put(receiptTrieRootHash, listOfSerializedNodesBytes)
if err != nil {
return nil, err
}

return receiptTrieRootHash, nil
}

func (ti *trieInteractor) saveReceiptTxHashLeafKey(leafHash []byte, leafData []byte) error {
receiptData := &state.Receipt{}
err := ti.marshaller.Unmarshal(receiptData, leafData)
if err != nil {
return err
}

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
}
if check.IfNil(args.Hasher) {
return process.ErrNilHasher
}
if check.IfNil(args.Marshaller) {
return process.ErrNilMarshalizer
}
if check.IfNil(args.ReceiptDataStorer) {
return dataRetriever.ErrNilReceiptsStorage
}

return nil
}

func (ti *trieInteractor) saveNodeData(currentNodeData *trie.CurrentNodeInfo, serializedNodes [][]byte) ([][]byte, error) {
if currentNodeData.Type != trie.LeafNodeType {
serializedNodes = append(serializedNodes, currentNodeData.SerializedNode)
return serializedNodes, nil
}

err := ti.storage.Put(currentNodeData.Hash, currentNodeData.SerializedNode)
if err != nil {
return nil, err
}

err = ti.saveReceiptTxHashLeafKey(currentNodeData.Hash, currentNodeData.Value)
if err != nil {
return nil, err
}

return serializedNodes, nil
}
Loading

0 comments on commit b482370

Please sign in to comment.