-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6450 from multiversx/receipts-data-trie
[lite-client] receipt data trie
- Loading branch information
Showing
13 changed files
with
526 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.