diff --git a/go/database/mpt/config.go b/go/database/mpt/config.go index 8db2393b1..c17d73f5b 100644 --- a/go/database/mpt/config.go +++ b/go/database/mpt/config.go @@ -10,7 +10,10 @@ package mpt -import "github.com/Fantom-foundation/Carmen/go/backend/stock" +import ( + "fmt" + "github.com/Fantom-foundation/Carmen/go/backend/stock" +) // MptConfig defines a set of configuration options for customizing the MPT // implementation. It is mainly intended to facilitate the accurate modeling @@ -94,7 +97,32 @@ func (c MptConfig) GetEncoders() ( stock.ValueEncoder[ValueNode], ) { - return getEncoder(c) + switch c.HashStorageLocation { + case HashStoredWithParent: + if c.TrackSuffixLengthsInLeafNodes { + return AccountNodeWithPathLengthEncoderWithChildHash{}, + BranchNodeEncoderWithChildHashes{}, + ExtensionNodeEncoderWithChildHash{}, + ValueNodeWithPathLengthEncoderWithoutNodeHash{} + } + return AccountNodeEncoderWithChildHash{}, + BranchNodeEncoderWithChildHashes{}, + ExtensionNodeEncoderWithChildHash{}, + ValueNodeEncoderWithoutNodeHash{} + case HashStoredWithNode: + if c.TrackSuffixLengthsInLeafNodes { + return AccountNodeWithPathLengthEncoderWithNodeHash{}, + BranchNodeEncoderWithNodeHash{}, + ExtensionNodeEncoderWithNodeHash{}, + ValueNodeWithPathLengthEncoderWithNodeHash{} + } + return AccountNodeEncoderWithNodeHash{}, + BranchNodeEncoderWithNodeHash{}, + ExtensionNodeEncoderWithNodeHash{}, + ValueNodeEncoderWithNodeHash{} + default: + panic(fmt.Sprintf("unknown mode: %v", c.HashStorageLocation)) + } } type HashStorageLocation bool diff --git a/go/database/mpt/config_test.go b/go/database/mpt/config_test.go index 4a506c2fb..446cb329b 100644 --- a/go/database/mpt/config_test.go +++ b/go/database/mpt/config_test.go @@ -10,12 +10,16 @@ package mpt -import "testing" +import ( + "fmt" + "github.com/Fantom-foundation/Carmen/go/backend/stock" + "testing" +) func TestMptConfig_GetEncoders(t *testing.T) { for _, config := range allMptConfigs { a1, b1, e1, v1 := config.GetEncoders() - a2, b2, e2, v2 := getEncoder(config) + a2, b2, e2, v2 := getExpectedEncoders(config) if a1 != a2 { t.Errorf("unexpected account node encoder, got %v, want %v", a1, a2) @@ -31,3 +35,37 @@ func TestMptConfig_GetEncoders(t *testing.T) { } } } + +func getExpectedEncoders(config MptConfig) ( + stock.ValueEncoder[AccountNode], + stock.ValueEncoder[BranchNode], + stock.ValueEncoder[ExtensionNode], + stock.ValueEncoder[ValueNode], +) { + switch config.HashStorageLocation { + case HashStoredWithParent: + if config.TrackSuffixLengthsInLeafNodes { + return AccountNodeWithPathLengthEncoderWithChildHash{}, + BranchNodeEncoderWithChildHashes{}, + ExtensionNodeEncoderWithChildHash{}, + ValueNodeWithPathLengthEncoderWithoutNodeHash{} + } + return AccountNodeEncoderWithChildHash{}, + BranchNodeEncoderWithChildHashes{}, + ExtensionNodeEncoderWithChildHash{}, + ValueNodeEncoderWithoutNodeHash{} + case HashStoredWithNode: + if config.TrackSuffixLengthsInLeafNodes { + return AccountNodeWithPathLengthEncoderWithNodeHash{}, + BranchNodeEncoderWithNodeHash{}, + ExtensionNodeEncoderWithNodeHash{}, + ValueNodeWithPathLengthEncoderWithNodeHash{} + } + return AccountNodeEncoderWithNodeHash{}, + BranchNodeEncoderWithNodeHash{}, + ExtensionNodeEncoderWithNodeHash{}, + ValueNodeEncoderWithNodeHash{} + default: + panic(fmt.Sprintf("unknown mode: %v", config.HashStorageLocation)) + } +} diff --git a/go/database/mpt/forest.go b/go/database/mpt/forest.go index e46f06aee..883cf9f43 100644 --- a/go/database/mpt/forest.go +++ b/go/database/mpt/forest.go @@ -148,7 +148,7 @@ func OpenInMemoryForest(directory string, mptConfig MptConfig, forestConfig Fore } }() - accountEncoder, branchEncoder, extensionEncoder, valueEncoder := getEncoder(mptConfig) + accountEncoder, branchEncoder, extensionEncoder, valueEncoder := mptConfig.GetEncoders() branches, err := memory.OpenStock[uint64, BranchNode](branchEncoder, directory+"/branches") if err != nil { return nil, err @@ -193,7 +193,7 @@ func OpenFileForest(directory string, mptConfig MptConfig, forestConfig ForestCo }() accountsDir, branchsDir, extensionsDir, valuesDir := getForestDirectories(directory) - accountEncoder, branchEncoder, extensionEncoder, valueEncoder := getEncoder(mptConfig) + accountEncoder, branchEncoder, extensionEncoder, valueEncoder := mptConfig.GetEncoders() branches, err := file.OpenStock[uint64, BranchNode](branchEncoder, branchsDir) if err != nil { return nil, err @@ -1045,40 +1045,6 @@ func getForestDirectories(root string) ( filepath.Join(root, "values") } -func getEncoder(config MptConfig) ( - stock.ValueEncoder[AccountNode], - stock.ValueEncoder[BranchNode], - stock.ValueEncoder[ExtensionNode], - stock.ValueEncoder[ValueNode], -) { - switch config.HashStorageLocation { - case HashStoredWithParent: - if config.TrackSuffixLengthsInLeafNodes { - return AccountNodeWithPathLengthEncoderWithChildHash{}, - BranchNodeEncoderWithChildHashes{}, - ExtensionNodeEncoderWithChildHash{}, - ValueNodeWithPathLengthEncoderWithoutNodeHash{} - } - return AccountNodeEncoderWithChildHash{}, - BranchNodeEncoderWithChildHashes{}, - ExtensionNodeEncoderWithChildHash{}, - ValueNodeEncoderWithoutNodeHash{} - case HashStoredWithNode: - if config.TrackSuffixLengthsInLeafNodes { - return AccountNodeWithPathLengthEncoderWithNodeHash{}, - BranchNodeEncoderWithNodeHash{}, - ExtensionNodeEncoderWithNodeHash{}, - ValueNodeWithPathLengthEncoderWithNodeHash{} - } - return AccountNodeEncoderWithNodeHash{}, - BranchNodeEncoderWithNodeHash{}, - ExtensionNodeEncoderWithNodeHash{}, - ValueNodeEncoderWithNodeHash{} - default: - panic(fmt.Sprintf("unknown mode: %v", config.HashStorageLocation)) - } -} - type writeBufferSink struct { forest *Forest } diff --git a/go/database/mpt/forest_test.go b/go/database/mpt/forest_test.go index d4a604d42..973c8ad97 100644 --- a/go/database/mpt/forest_test.go +++ b/go/database/mpt/forest_test.go @@ -1610,7 +1610,7 @@ func testForest_WriteBufferRecoveryIsThreadSafe(t *testing.T, withConcurrentNode // synchronization features of the file-based stock which have caused problems // in the past. func openFileShadowForest(directory string, mptConfig MptConfig, forestConfig ForestConfig) (*Forest, error) { - accountEncoder, branchEncoder, extensionEncoder, valueEncoder := getEncoder(mptConfig) + accountEncoder, branchEncoder, extensionEncoder, valueEncoder := mptConfig.GetEncoders() branchesA, err := file.OpenStock[uint64, BranchNode](branchEncoder, directory+"/A/branches") if err != nil { return nil, err diff --git a/go/database/mpt/verification.go b/go/database/mpt/verification.go index 55ffcf0e4..56a0cef5d 100644 --- a/go/database/mpt/verification.go +++ b/go/database/mpt/verification.go @@ -120,7 +120,7 @@ func verifyForest(directory string, config MptConfig, roots []Root, source *veri // Verify stock data structures. observer.Progress("Checking meta-data ...") - accountEncoder, branchEncoder, extensionEncoder, valueEncoder := getEncoder(config) + accountEncoder, branchEncoder, extensionEncoder, valueEncoder := config.GetEncoders() if err := file.VerifyStock[uint64](directory+"/accounts", accountEncoder); err != nil { return err } @@ -694,7 +694,7 @@ func openVerificationNodeSource(ctx context.Context, directory string, config Mp } success := false - accountEncoder, branchEncoder, extensionEncoder, valueEncoder := getEncoder(config) + accountEncoder, branchEncoder, extensionEncoder, valueEncoder := config.GetEncoders() branches, err := file.OpenStock[uint64, BranchNode](branchEncoder, directory+"/branches") if err != nil { return nil, err diff --git a/go/database/mpt/verification_test.go b/go/database/mpt/verification_test.go index 82f5fb761..1fdef25b8 100644 --- a/go/database/mpt/verification_test.go +++ b/go/database/mpt/verification_test.go @@ -128,7 +128,7 @@ func TestVerification_ModifiedFileIsDetected(t *testing.T) { func TestVerification_ModifiedRootIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, encoder, _, _ := getEncoder(config) + _, encoder, _, _ := config.GetEncoders() root := NewNodeReference(EmptyId()) for i := 0; i < len(roots); i++ { @@ -175,7 +175,7 @@ func TestVerification_ModifiedRootIsDetected(t *testing.T) { func TestVerification_AccountBalanceModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.info.Balance = amount.Add(node.info.Balance, amount.New(1)) @@ -189,7 +189,7 @@ func TestVerification_AccountBalanceModificationIsDetected(t *testing.T) { func TestVerification_AccountNonceModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.info.Nonce[2]++ @@ -203,7 +203,7 @@ func TestVerification_AccountNonceModificationIsDetected(t *testing.T) { func TestVerification_AccountCodeHashModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.info.CodeHash[2]++ @@ -217,7 +217,7 @@ func TestVerification_AccountCodeHashModificationIsDetected(t *testing.T) { func TestVerification_AccountStorageModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.storage = NewNodeReference(ValueId(123456789)) // invalid in test forest @@ -234,7 +234,7 @@ func TestVerification_AccountNodeHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithNode { return } - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.hash[3]++ @@ -251,7 +251,7 @@ func TestVerification_AccountStorageHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithParent { return } - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.storageHash[3]++ @@ -265,7 +265,7 @@ func TestVerification_AccountStorageHashModificationIsDetected(t *testing.T) { func TestVerification_BranchChildIdModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, encoder, _, _ := getEncoder(config) + _, encoder, _, _ := config.GetEncoders() modifyNode(t, dir+"/branches", encoder, func(node *BranchNode) { node.children[8] = NewNodeReference(ValueId(123456789)) // does not exist in test forest @@ -282,7 +282,7 @@ func TestVerification_BranchNodeHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithNode { return } - _, encoder, _, _ := getEncoder(config) + _, encoder, _, _ := config.GetEncoders() modifyNode(t, dir+"/branches", encoder, func(node *BranchNode) { node.hash[4]++ @@ -299,7 +299,7 @@ func TestVerification_BranchChildHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithParent { return } - _, encoder, _, _ := getEncoder(config) + _, encoder, _, _ := config.GetEncoders() modifyNode(t, dir+"/branches", encoder, func(node *BranchNode) { for i, child := range node.children { @@ -318,7 +318,7 @@ func TestVerification_BranchChildHashModificationIsDetected(t *testing.T) { func TestVerification_ExtensionPathModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, _, encoder, _ := getEncoder(config) + _, _, encoder, _ := config.GetEncoders() modifyNode(t, dir+"/extensions", encoder, func(node *ExtensionNode) { node.path.path[0] = ^node.path.path[0] @@ -332,7 +332,7 @@ func TestVerification_ExtensionPathModificationIsDetected(t *testing.T) { func TestVerification_ExtensionNextModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, _, encoder, _ := getEncoder(config) + _, _, encoder, _ := config.GetEncoders() modifyNode(t, dir+"/extensions", encoder, func(node *ExtensionNode) { node.next = NewNodeReference(BranchId(123456789)) @@ -349,7 +349,7 @@ func TestVerification_ExtensionNodeHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithNode { return } - _, _, encoder, _ := getEncoder(config) + _, _, encoder, _ := config.GetEncoders() modifyNode(t, dir+"/extensions", encoder, func(node *ExtensionNode) { node.hash[24]++ @@ -366,7 +366,7 @@ func TestVerification_ExtensionNextHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithParent { return } - _, _, encoder, _ := getEncoder(config) + _, _, encoder, _ := config.GetEncoders() modifyNode(t, dir+"/extensions", encoder, func(node *ExtensionNode) { node.nextHash[24]++ @@ -380,7 +380,7 @@ func TestVerification_ExtensionNextHashModificationIsDetected(t *testing.T) { func TestVerification_ValueKeyModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, _, _, encoder := getEncoder(config) + _, _, _, encoder := config.GetEncoders() modifyNode(t, dir+"/values", encoder, func(node *ValueNode) { node.key[5]++ @@ -394,7 +394,7 @@ func TestVerification_ValueKeyModificationIsDetected(t *testing.T) { func TestVerification_ValueModificationIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - _, _, _, encoder := getEncoder(config) + _, _, _, encoder := config.GetEncoders() modifyNode(t, dir+"/values", encoder, func(node *ValueNode) { node.value[12]++ @@ -411,7 +411,7 @@ func TestVerification_ValueNodeHashModificationIsDetected(t *testing.T) { if config.HashStorageLocation != HashStoredWithNode { return } - _, _, _, encoder := getEncoder(config) + _, _, _, encoder := config.GetEncoders() modifyNode(t, dir+"/values", encoder, func(node *ValueNode) { node.hash[12]++ @@ -425,7 +425,7 @@ func TestVerification_ValueNodeHashModificationIsDetected(t *testing.T) { func TestVerification_MissingCodeHashInCodeFileIsDetected(t *testing.T) { runVerificationTest(t, func(t *testing.T, dir string, config MptConfig, roots []Root) { - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() missingHash := common.Keccak256([]byte{2}) @@ -641,7 +641,7 @@ func TestVerification_ForestVerificationObserverReportsError(t *testing.T) { observer.EXPECT().EndVerification(gomock.Not(nil)), ) - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.info.Balance = amount.Add(node.info.Balance, amount.New(1)) @@ -664,7 +664,7 @@ func TestVerification_VerificationObserverReportsError(t *testing.T) { observer.EXPECT().EndVerification(gomock.Not(nil)), ) - encoder, _, _, _ := getEncoder(config) + encoder, _, _, _ := config.GetEncoders() modifyNode(t, dir+"/accounts", encoder, func(node *AccountNode) { node.info.Balance = amount.Add(node.info.Balance, amount.New(1))