Skip to content
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

[chain] Defer State Root Generation #425

Merged
merged 33 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b15e137
add first todo
patrick-ogrady Aug 27, 2023
5fe46ee
cleanup README point
patrick-ogrady Aug 27, 2023
dd01be6
update mocks
patrick-ogrady Aug 27, 2023
98f072d
add poc
patrick-ogrady Aug 27, 2023
1fde94f
add span for waitRoot
patrick-ogrady Aug 27, 2023
6c5cf69
fix VerifySignatures
patrick-ogrady Aug 27, 2023
ba39b5d
make signature verification a config
patrick-ogrady Aug 27, 2023
6be6c04
add a TODO for splitting parallelism
patrick-ogrady Aug 27, 2023
e7b37a6
update to tip of dev
patrick-ogrady Aug 28, 2023
99022d3
split parallelism
patrick-ogrady Aug 28, 2023
b8e62f5
set cores 50/50
patrick-ogrady Aug 28, 2023
b3a0a99
wait root calc metric
patrick-ogrady Aug 28, 2023
0636c17
add more TODOs
patrick-ogrady Aug 28, 2023
ef6c44d
update logic to handle unprocessed block post-state sync
patrick-ogrady Aug 28, 2023
89cf991
more progress
patrick-ogrady Aug 28, 2023
684d736
add more notes
patrick-ogrady Aug 28, 2023
f3eb026
use nil in vm
patrick-ogrady Aug 28, 2023
64a2601
finish comments on View
patrick-ogrady Aug 28, 2023
8bfa8a0
nits
patrick-ogrady Aug 28, 2023
bf2f378
comment nit
patrick-ogrady Aug 28, 2023
61bf66d
comment nits
patrick-ogrady Aug 28, 2023
4f77c6f
fix genesis handling
patrick-ogrady Aug 28, 2023
395a296
change variable name
patrick-ogrady Aug 28, 2023
ea58c3e
use math.Max
patrick-ogrady Aug 28, 2023
e995d5a
add more logging
patrick-ogrady Aug 28, 2023
51e63d8
more cleanup
patrick-ogrady Aug 28, 2023
fa73457
add TODO for invariant change
patrick-ogrady Aug 28, 2023
689d3bf
[chain] Remove Parent Block Dependency during Verify (#427)
patrick-ogrady Aug 31, 2023
0203327
populate more of README
patrick-ogrady Aug 31, 2023
7d6a81f
commit WIP
patrick-ogrady Aug 31, 2023
b4a935e
progress
patrick-ogrady Sep 1, 2023
1fe04cc
final pass on README
patrick-ogrady Sep 1, 2023
d50d88e
Merge branch 'main' into defer-root-v3
patrick-ogrady Sep 1, 2023
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
Prev Previous commit
Next Next commit
[chain] Remove Parent Block Dependency during Verify (#427)
* add TODO

* remove parent fetch

* remove parent block from innerVerify

* add verify context

* cleanup VerifyContext call

* working on clarifying GetVerifyContext/View

* keep cleaning up

* add specific conditional for height

* update verification context handling

* update wording in view to explain why we need accepted handling

* add more comments to main path

* update interface

* use preferred block directly

* drop verify

* fix lint

* update state manager

* add note about GetBlockIDByHeight

* finish comment about handling blocks

* make sure keys in set

* add todo for genesis handling

* update genesis block handling

* add more logs

* e2e passing

* address chain nits

* better comment genesis

* extra VM comments

* add TODO

* clarify note about verification status
  • Loading branch information
patrick-ogrady authored Aug 31, 2023
commit 689d3bffe4f7af8dde609c58956be93f4d287e30
252 changes: 149 additions & 103 deletions chain/block.go

Large diffs are not rendered by default.

38 changes: 20 additions & 18 deletions chain/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"time"

"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/ids"
smblock "github.com/ava-labs/avalanchego/snow/engine/snowman/block"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/math"
Expand Down Expand Up @@ -61,19 +60,17 @@ func HandlePreExecute(log logging.Logger, err error) bool {
func BuildBlock(
ctx context.Context,
vm VM,
preferred ids.ID,
parent *StatelessBlock,
blockContext *smblock.Context,
) (*StatelessBlock, error) {
ctx, span := vm.Tracer().Start(ctx, "chain.BuildBlock")
defer span.End()
log := vm.Logger()

// Setup new block
parent, err := vm.GetStatelessBlock(ctx, preferred)
if err != nil {
log.Warn("block building failed: couldn't get parent", zap.Error(err))
return nil, err
}
// We don't need to fetch the [VerifyContext] because
// we will always have a block to build on.

// Select next timestamp
nextTime := time.Now().UnixMilli()
r := vm.Rules(nextTime)
if nextTime < parent.Tmstmp+r.GetMinBlockGap() {
Expand All @@ -82,10 +79,13 @@ func BuildBlock(
}
b := NewBlock(vm, parent, nextTime)

// Fetch state to build on
// Fetch view where we will apply block state transitions
//
// If the parent block is not yet verified, we will attempt to
// execute it.
mempoolSize := vm.Mempool().Len(ctx)
changesEstimate := math.Min(mempoolSize, maxViewPreallocation)
parentView, err := parent.View(ctx, nil)
parentView, err := parent.View(ctx, nil, true)
if err != nil {
log.Warn("block building failed: couldn't get parent db", zap.Error(err))
return nil, err
Expand Down Expand Up @@ -454,21 +454,23 @@ func BuildBlock(
vm.RecordEmptyBlockBuilt()
}

// Set scope for [tstate] changes
// Update chain metadata
heightKey := HeightKey(sm.HeightKey())
heightKeyStr := string(heightKey)
timestampKey := TimestampKey(b.vm.StateManager().TimestampKey())
timestampKeyStr := string(timestampKey)
feeKeyStr := string(feeKey)
ts.SetScope(ctx, set.Of(heightKeyStr, feeKeyStr), map[string][]byte{
heightKeyStr: binary.BigEndian.AppendUint64(nil, parent.Hght),
feeKeyStr: parentFeeManager.Bytes(),
ts.SetScope(ctx, set.Of(heightKeyStr, timestampKeyStr, feeKeyStr), map[string][]byte{
heightKeyStr: binary.BigEndian.AppendUint64(nil, parent.Hght),
timestampKeyStr: binary.BigEndian.AppendUint64(nil, uint64(parent.Tmstmp)),
feeKeyStr: parentFeeManager.Bytes(),
})

// Store height in state to prevent duplicate roots
if err := ts.Insert(ctx, heightKey, binary.BigEndian.AppendUint64(nil, b.Hght)); err != nil {
return nil, fmt.Errorf("%w: unable to insert height", err)
}

// Store fee parameters
if err := ts.Insert(ctx, timestampKey, binary.BigEndian.AppendUint64(nil, uint64(b.Tmstmp))); err != nil {
return nil, fmt.Errorf("%w: unable to insert timestamp", err)
}
if err := ts.Insert(ctx, feeKey, feeManager.Bytes()); err != nil {
return nil, fmt.Errorf("%w: unable to insert fees", err)
}
Expand Down
5 changes: 5 additions & 0 deletions chain/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ const (
// ranges (so, we can't expose a way to modify this over time).
MaxOutgoingWarpChunks = 4
HeightKeyChunks = 1
TimestampKeyChunks = 1
FeeKeyChunks = 8 // 96 (per dimension) * 5 (num dimensions)
)

func HeightKey(prefix []byte) []byte {
return keys.EncodeChunks(prefix, HeightKeyChunks)
}

func TimestampKey(prefix []byte) []byte {
return keys.EncodeChunks(prefix, TimestampKeyChunks)
}

func FeeKey(prefix []byte) []byte {
return keys.EncodeChunks(prefix, FeeKeyChunks)
}
8 changes: 8 additions & 0 deletions chain/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type VM interface {
SetLastAccepted(*StatelessBlock) error
GetStatelessBlock(context.Context, ids.ID) (*StatelessBlock, error)

GetVerifyContext(ctx context.Context, blockHeight uint64, parent ids.ID) (VerifyContext, error)

State() (merkledb.MerkleDB, error)
StateManager() StateManager
ValidatorState() validators.State
Expand Down Expand Up @@ -82,6 +84,11 @@ type VM interface {
RecordClearedMempool()
}

type VerifyContext interface {
View(ctx context.Context, blockRoot *ids.ID, verify bool) (state.View, error)
IsRepeat(ctx context.Context, oldestAllowed int64, txs []*Transaction, marker set.Bits, stop bool) (set.Bits, error)
}

type Mempool interface {
Len(context.Context) int // items
Size(context.Context) int // bytes
Expand Down Expand Up @@ -156,6 +163,7 @@ type Rules interface {
// use. This will be handled by the hypersdk.
type StateManager interface {
HeightKey() []byte
TimestampKey() []byte
FeeKey() []byte

IncomingWarpKeyPrefix(sourceChainID ids.ID, msgID ids.ID) []byte
Expand Down
1 change: 1 addition & 0 deletions chain/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (
ErrInvalidSurplus = errors.New("invalid surplus fee")
ErrStateRootMismatch = errors.New("state root mismatch")
ErrInvalidResult = errors.New("invalid result")
ErrInvalidBlockHeight = errors.New("invalid block height")

// Tx Correctness
ErrInvalidSignature = errors.New("invalid signature")
Expand Down
4 changes: 4 additions & 0 deletions examples/morpheusvm/storage/state_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ func (*StateManager) HeightKey() []byte {
return HeightKey()
}

func (*StateManager) TimestampKey() []byte {
return TimestampKey()
}

func (*StateManager) FeeKey() []byte {
return FeeKey()
}
Expand Down
27 changes: 17 additions & 10 deletions examples/morpheusvm/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ type ReadState func(context.Context, [][]byte) ([][]byte, []error)
// 0x0/ (balance)
// -> [owner] => balance
// 0x1/ (hypersdk-height)
// 0x2/ (hypersdk-fee)
// 0x3/ (hypersdk-incoming warp)
// 0x4/ (hypersdk-outgoing warp)
// 0x2/ (hypersdk-timestamp)
// 0x3/ (hypersdk-fee)
// 0x4/ (hypersdk-incoming warp)
// 0x5/ (hypersdk-outgoing warp)

const (
// metaDB
Expand All @@ -44,18 +45,20 @@ const (
// stateDB
balancePrefix = 0x0
heightPrefix = 0x1
feePrefix = 0x2
incomingWarpPrefix = 0x3
outgoingWarpPrefix = 0x4
timestampPrefix = 0x2
feePrefix = 0x3
incomingWarpPrefix = 0x4
outgoingWarpPrefix = 0x5
)

const BalanceChunks uint16 = 1

var (
failureByte = byte(0x0)
successByte = byte(0x1)
heightKey = []byte{heightPrefix}
feeKey = []byte{feePrefix}
failureByte = byte(0x0)
successByte = byte(0x1)
heightKey = []byte{heightPrefix}
timestampKey = []byte{timestampPrefix}
feeKey = []byte{feePrefix}

balanceKeyPool = sync.Pool{
New: func() any {
Expand Down Expand Up @@ -256,6 +259,10 @@ func HeightKey() (k []byte) {
return heightKey
}

func TimestampKey() (k []byte) {
return timestampKey
}

func FeeKey() (k []byte) {
return feeKey
}
Expand Down
4 changes: 4 additions & 0 deletions examples/tokenvm/controller/state_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func (*StateManager) HeightKey() []byte {
return storage.HeightKey()
}

func (*StateManager) TimestampKey() []byte {
return storage.TimestampKey()
}

func (*StateManager) FeeKey() []byte {
return storage.HeightKey()
}
Expand Down
27 changes: 17 additions & 10 deletions examples/tokenvm/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ type ReadState func(context.Context, [][]byte) ([][]byte, []error)
// 0x3/ (loans)
// -> [assetID|destination] => amount
// 0x4/ (hypersdk-height)
// 0x5/ (hypersdk-fee)
// 0x6/ (hypersdk-incoming warp)
// 0x7/ (hypersdk-outgoing warp)
// 0x5/ (hypersdk-timestamp)
// 0x6/ (hypersdk-fee)
// 0x7/ (hypersdk-incoming warp)
// 0x8/ (hypersdk-outgoing warp)

const (
// metaDB
Expand All @@ -51,9 +52,10 @@ const (
orderPrefix = 0x2
loanPrefix = 0x3
heightPrefix = 0x4
feePrefix = 0x5
incomingWarpPrefix = 0x6
outgoingWarpPrefix = 0x7
timestampPrefix = 0x5
feePrefix = 0x6
incomingWarpPrefix = 0x7
outgoingWarpPrefix = 0x8
)

const (
Expand All @@ -64,10 +66,11 @@ const (
)

var (
failureByte = byte(0x0)
successByte = byte(0x1)
heightKey = []byte{heightPrefix}
feeKey = []byte{feePrefix}
failureByte = byte(0x0)
successByte = byte(0x1)
heightKey = []byte{heightPrefix}
timestampKey = []byte{timestampPrefix}
feeKey = []byte{feePrefix}

balanceKeyPool = sync.Pool{
New: func() any {
Expand Down Expand Up @@ -538,6 +541,10 @@ func HeightKey() (k []byte) {
return heightKey
}

func TimestampKey() (k []byte) {
return timestampKey
}

func FeeKey() (k []byte) {
return feeKey
}
Expand Down
11 changes: 6 additions & 5 deletions vm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
)

var (
ErrNotAdded = errors.New("not added")
ErrDropped = errors.New("dropped")
ErrNotReady = errors.New("not ready")
ErrStateMissing = errors.New("state missing")
ErrStateSyncing = errors.New("state still syncing")
ErrNotAdded = errors.New("not added")
ErrDropped = errors.New("dropped")
ErrNotReady = errors.New("not ready")
ErrStateMissing = errors.New("state missing")
ErrStateSyncing = errors.New("state still syncing")
ErrUnexpectedStateRoot = errors.New("unexpected state root")
)
3 changes: 3 additions & 0 deletions vm/resolutions.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func (vm *VM) Verified(ctx context.Context, b *chain.StatelessBlock) {
zap.Stringer("blkID", b.ID()),
zap.Uint64("height", b.Hght),
zap.Int("txs", len(b.Txs)),
zap.Stringer("parent root", b.StateRoot),
zap.Bool("state ready", vm.StateReady()),
zap.Any("unit prices", fm.UnitPrices()),
zap.Any("units consumed", fm.UnitsConsumed()),
Expand All @@ -128,6 +129,7 @@ func (vm *VM) Verified(ctx context.Context, b *chain.StatelessBlock) {
zap.Stringer("blkID", b.ID()),
zap.Uint64("height", b.Hght),
zap.Int("txs", len(b.Txs)),
zap.Stringer("parent root", b.StateRoot),
zap.Bool("state ready", vm.StateReady()),
)
}
Expand Down Expand Up @@ -301,6 +303,7 @@ func (vm *VM) Accepted(ctx context.Context, b *chain.StatelessBlock) {
zap.Stringer("blkID", b.ID()),
zap.Uint64("height", b.Hght),
zap.Int("txs", len(b.Txs)),
zap.Stringer("parent root", b.StateRoot),
zap.Int("size", len(b.Bytes())),
zap.Int("dropped mempool txs", len(removed)),
zap.Bool("state ready", vm.StateReady()),
Expand Down
Loading