Skip to content

Merkle-ize X-Chain State #3732

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions database/memdb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package memdb

import (
"context"
"fmt"
"slices"
"strings"
"sync"
Expand Down Expand Up @@ -38,6 +39,21 @@ func New() *Database {
return NewWithSize(DefaultSize)
}

// Copy returns a Database with the same key-value pairs as db
func Copy(db *Database) (*Database, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need this utility to be able to copy the memdb between VM instances, since closing a database makes it so that it's unusable afterwards.

db.lock.Lock()
defer db.lock.Unlock()

result := New()
for k, v := range db.db {
if err := result.Put([]byte(k), v); err != nil {
return nil, fmt.Errorf("failed to insert key: %w", err)
}
}

return result, nil
}

// NewWithSize returns a map pre-allocated to the provided size with the
// Database interface methods implemented.
func NewWithSize(size int) *Database {
Expand Down
9 changes: 7 additions & 2 deletions vms/avm/block/executor/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func (b *Block) Verify(context.Context) error {
return nil
}

func (b *Block) Accept(context.Context) error {
func (b *Block) Accept(ctx context.Context) error {
blkID := b.ID()
defer b.manager.free(blkID)

Expand Down Expand Up @@ -254,12 +254,17 @@ func (b *Block) Accept(context.Context) error {
return err
}

checksum, err := b.manager.state.Checksum(ctx)
if err != nil {
return fmt.Errorf("failed to get checksum: %w", err)
}

b.manager.backend.Ctx.Log.Trace(
"accepted block",
zap.Stringer("blkID", blkID),
zap.Uint64("height", b.Height()),
zap.Stringer("parentID", b.Parent()),
zap.Stringer("checksum", b.manager.state.Checksum()),
zap.Stringer("checksum", checksum),
)
return nil
}
Expand Down
18 changes: 9 additions & 9 deletions vms/avm/block/executor/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestBlockVerify(t *testing.T) {
parentID := ids.GenerateTestID()
mockBlock.EXPECT().Parent().Return(parentID).AnyTimes()

mockState := statemock.NewState(ctrl)
mockState := statemock.NewMockInterface(ctrl)
mockState.EXPECT().GetBlock(parentID).Return(nil, errTest)
return &Block{
Block: mockBlock,
Expand Down Expand Up @@ -195,7 +195,7 @@ func TestBlockVerify(t *testing.T) {
parentID := ids.GenerateTestID()
mockBlock.EXPECT().Parent().Return(parentID).AnyTimes()

mockState := statemock.NewState(ctrl)
mockState := statemock.NewMockInterface(ctrl)
mockParentBlock := block.NewMockBlock(ctrl)
mockParentBlock.EXPECT().Height().Return(blockHeight) // Should be blockHeight - 1
mockState.EXPECT().GetBlock(parentID).Return(mockParentBlock, nil)
Expand Down Expand Up @@ -626,7 +626,7 @@ func TestBlockAccept(t *testing.T) {
mempool, err := mempool.New("", prometheus.NewRegistry(), nil)
require.NoError(t, err)

mockManagerState := statemock.NewState(ctrl)
mockManagerState := statemock.NewMockInterface(ctrl)
mockManagerState.EXPECT().CommitBatch().Return(nil, errTest)
mockManagerState.EXPECT().Abort()

Expand Down Expand Up @@ -660,7 +660,7 @@ func TestBlockAccept(t *testing.T) {
mempool, err := mempool.New("", prometheus.NewRegistry(), nil)
require.NoError(t, err)

mockManagerState := statemock.NewState(ctrl)
mockManagerState := statemock.NewMockInterface(ctrl)
// Note the returned batch is nil but not used
// because we mock the call to shared memory
mockManagerState.EXPECT().CommitBatch().Return(nil, nil)
Expand Down Expand Up @@ -699,7 +699,7 @@ func TestBlockAccept(t *testing.T) {
mempool, err := mempool.New("", prometheus.NewRegistry(), nil)
require.NoError(t, err)

mockManagerState := statemock.NewState(ctrl)
mockManagerState := statemock.NewMockInterface(ctrl)
// Note the returned batch is nil but not used
// because we mock the call to shared memory
mockManagerState.EXPECT().CommitBatch().Return(nil, nil)
Expand Down Expand Up @@ -744,12 +744,12 @@ func TestBlockAccept(t *testing.T) {
mempool, err := mempool.New("", prometheus.NewRegistry(), nil)
require.NoError(t, err)

mockManagerState := statemock.NewState(ctrl)
mockManagerState := statemock.NewMockInterface(ctrl)
// Note the returned batch is nil but not used
// because we mock the call to shared memory
mockManagerState.EXPECT().CommitBatch().Return(nil, nil)
mockManagerState.EXPECT().Abort()
mockManagerState.EXPECT().Checksum().Return(ids.Empty)
mockManagerState.EXPECT().Checksum(gomock.Any()).Return(ids.Empty, nil)

mockSharedMemory := atomicmock.NewSharedMemory(ctrl)
mockSharedMemory.EXPECT().Apply(gomock.Any(), gomock.Any()).Return(nil)
Expand Down Expand Up @@ -851,7 +851,7 @@ func TestBlockReject(t *testing.T) {
require.NoError(t, err)

lastAcceptedID := ids.GenerateTestID()
mockState := statemock.NewState(ctrl)
mockState := statemock.NewMockInterface(ctrl)
mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes()
mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes()

Expand Down Expand Up @@ -904,7 +904,7 @@ func TestBlockReject(t *testing.T) {
require.NoError(t, err)

lastAcceptedID := ids.GenerateTestID()
mockState := statemock.NewState(ctrl)
mockState := statemock.NewMockInterface(ctrl)
mockState.EXPECT().GetLastAccepted().Return(lastAcceptedID).AnyTimes()
mockState.EXPECT().GetTimestamp().Return(time.Now()).AnyTimes()

Expand Down
4 changes: 2 additions & 2 deletions vms/avm/block/executor/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type Manager interface {
func NewManager(
mempool mempool.Mempool,
metrics metrics.Metrics,
state state.State,
state state.Interface,
backend *executor.Backend,
clk *mockable.Clock,
onAccept func(*txs.Tx) error,
Expand All @@ -72,7 +72,7 @@ func NewManager(

type manager struct {
backend *executor.Backend
state state.State
state state.Interface
metrics metrics.Metrics
mempool mempool.Mempool
clk *mockable.Clock
Expand Down
10 changes: 5 additions & 5 deletions vms/avm/block/executor/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestManagerGetStatelessBlock(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)

state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
m := &manager{
state: state,
blkIDToState: map[ids.ID]*blockState{},
Expand Down Expand Up @@ -72,7 +72,7 @@ func TestManagerGetState(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)

s := statemock.NewState(ctrl)
s := statemock.NewMockInterface(ctrl)
m := &manager{
state: s,
blkIDToState: map[ids.ID]*blockState{},
Expand Down Expand Up @@ -160,7 +160,7 @@ func TestManagerVerifyTx(t *testing.T) {
lastAcceptedID := ids.GenerateTestID()

// These values don't matter for this test
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
state.EXPECT().GetTimestamp().Return(time.Time{})

Expand Down Expand Up @@ -190,7 +190,7 @@ func TestManagerVerifyTx(t *testing.T) {
lastAcceptedID := ids.GenerateTestID()

// These values don't matter for this test
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
state.EXPECT().GetTimestamp().Return(time.Time{})

Expand Down Expand Up @@ -220,7 +220,7 @@ func TestManagerVerifyTx(t *testing.T) {
lastAcceptedID := ids.GenerateTestID()

// These values don't matter for this test
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetLastAccepted().Return(lastAcceptedID)
state.EXPECT().GetTimestamp().Return(time.Time{})

Expand Down
3 changes: 2 additions & 1 deletion vms/avm/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ func setup(tb testing.TB, c *envConfig) *environment {
}

vm := &VM{
Config: vmStaticConfig,
Config: vmStaticConfig,
StateMigrationFactory: NoStateMigrationFactory{},
}

vmDynamicConfig := DefaultConfig
Expand Down
8 changes: 7 additions & 1 deletion vms/avm/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@ type Factory struct {
}

func (f *Factory) New(logging.Logger) (interface{}, error) {
return &VM{Config: f.Config}, nil
return &VM{
Config: f.Config,
StateMigrationFactory: GForkStateMigrationFactory{
CommitFrequency: 1_000,
},
},
nil
}
16 changes: 8 additions & 8 deletions vms/avm/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2536,7 +2536,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
{
name: "block height not found",
serviceAndExpectedBlockFunc: func(_ *testing.T, ctrl *gomock.Controller) (*Service, interface{}) {
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(ids.Empty, database.ErrNotFound)

manager := executormock.NewManager(ctrl)
Expand All @@ -2556,7 +2556,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
{
name: "block not found",
serviceAndExpectedBlockFunc: func(_ *testing.T, ctrl *gomock.Controller) (*Service, interface{}) {
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(blockID, nil)

manager := executormock.NewManager(ctrl)
Expand All @@ -2581,7 +2581,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
block.EXPECT().InitCtx(gomock.Any())
block.EXPECT().Txs().Return(nil)

state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(blockID, nil)

manager := executormock.NewManager(ctrl)
Expand All @@ -2606,7 +2606,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
blockBytes := []byte("hi mom")
block.EXPECT().Bytes().Return(blockBytes)

state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(blockID, nil)

expected, err := formatting.Encode(formatting.Hex, blockBytes)
Expand Down Expand Up @@ -2634,7 +2634,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
blockBytes := []byte("hi mom")
block.EXPECT().Bytes().Return(blockBytes)

state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(blockID, nil)

expected, err := formatting.Encode(formatting.HexC, blockBytes)
Expand Down Expand Up @@ -2662,7 +2662,7 @@ func TestServiceGetBlockByHeight(t *testing.T) {
blockBytes := []byte("hi mom")
block.EXPECT().Bytes().Return(blockBytes)

state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetBlockIDAtHeight(blockHeight).Return(blockID, nil)

expected, err := formatting.Encode(formatting.HexNC, blockBytes)
Expand Down Expand Up @@ -2740,7 +2740,7 @@ func TestServiceGetHeight(t *testing.T) {
{
name: "block not found",
serviceFunc: func(ctrl *gomock.Controller) *Service {
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetLastAccepted().Return(blockID)

manager := executormock.NewManager(ctrl)
Expand All @@ -2760,7 +2760,7 @@ func TestServiceGetHeight(t *testing.T) {
{
name: "happy path",
serviceFunc: func(ctrl *gomock.Controller) *Service {
state := statemock.NewState(ctrl)
state := statemock.NewMockInterface(ctrl)
state.EXPECT().GetLastAccepted().Return(blockID)

block := block.NewMockBlock(ctrl)
Expand Down
2 changes: 1 addition & 1 deletion vms/avm/state/mocks_generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ package state

//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/chain.go -mock_names=Chain=Chain . Chain
//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/diff.go -mock_names=Diff=Diff . Diff
//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/state.go -mock_names=State=State . State
//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/state.go -mock_names=State=Interface . Interface
Loading
Loading