mirror of
https://github.com/luxfi/node.git
synced 2026-07-29 08:36:26 +00:00
decomplect: collapse upgrade-prefixed block-type variants to single canonical (StandardBlock/ProposalBlock/AbortBlock/CommitBlock); Visitor 9→4 methods; codec single-type registration; old chaindata wire compat broken (intentional)
Phase 2 of the upstream-upgrade purge per ~/work/lux/proofs/UPGRADE_RIP.md.
P-Chain (vms/platformvm/block):
- 9 block-type variants collapsed to 4 canonical kinds:
Banff{Standard,Proposal,Abort,Commit}Block +
Apricot{Standard,Proposal,Abort,Commit,Atomic}Block
→ {Standard,Proposal,Abort,Commit}Block.
Banff types were the canonical newer format (carry per-block timestamp),
so they win; Apricot embedding is gone. Atomic block deleted entirely
(verifier permanently rejects atomic txs under always-on, so the type
has no role).
- Visitor interface: 9 methods → 4 (Standard, Proposal, Abort, Commit).
All visitor implementations (verifier, acceptor, rejector, options,
blockMetrics) collapsed to the 4 canonical methods.
- Codec: RegisterApricotTypes + RegisterBanffTypes consolidated into
RegisterBlockTypes; only 4 type IDs registered (down from 9). Internal
SkipRegistrations counts preserved to keep tx codec IDs stable.
- Tx codec: RegisterApricot/Banff/Durango/Etna/GraniteTypes consolidated
into a single RegisterTypes that registers tx types in their canonical
on-disk order (no upgrade-name partitioning).
- block.NewBanff* / NewApricot* constructors → NewStandardBlock /
NewProposalBlock / NewAbortBlock / NewCommitBlock.
- packDurangoBlockTxs (legacy non-dynamic-fee path) deleted; only
packEtnaBlockTxs remains as the canonical block-packing helper.
- state.init() seeds genesis CommitBlock with upgrade.InitiallyActiveTime
as the canonical timestamp (was zero-time on the deleted ApricotCommitBlock).
Old chaindata wire compat is intentionally broken: codec type IDs for the
deleted block variants are gone, so any pre-rip P-Chain chaindata cannot
be replayed. This matches the user directive 'no backwards compatibility
only forwards perfection'.
Build: `GOCACHE=/tmp/gocache-decomplect-r2 GOWORK=off go build ./...` green.
Tests that pin to Apricot/Banff block-type names land in Phase 4.
This commit is contained in:
@@ -12,84 +12,34 @@ import (
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
var (
|
||||
_ BanffBlock = (*BanffAbortBlock)(nil)
|
||||
_ Block = (*ApricotAbortBlock)(nil)
|
||||
)
|
||||
var _ Block = (*AbortBlock)(nil)
|
||||
|
||||
type BanffAbortBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
ApricotAbortBlock `serialize:"true"`
|
||||
}
|
||||
|
||||
func (b *BanffAbortBlock) Timestamp() time.Time {
|
||||
return time.Unix(int64(b.Time), 0)
|
||||
}
|
||||
|
||||
func (b *BanffAbortBlock) Visit(v Visitor) error {
|
||||
return v.BanffAbortBlock(b)
|
||||
}
|
||||
|
||||
func NewBanffAbortBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
) (*BanffAbortBlock, error) {
|
||||
blk := &BanffAbortBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
ApricotAbortBlock: ApricotAbortBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
},
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
type ApricotAbortBlock struct {
|
||||
// AbortBlock is the canonical P-Chain abort outcome of a ProposalBlock.
|
||||
type AbortBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
CommonBlock `serialize:"true"`
|
||||
}
|
||||
|
||||
func (b *ApricotAbortBlock) initialize(bytes []byte) error {
|
||||
func (b *AbortBlock) Timestamp() time.Time { return time.Unix(int64(b.Time), 0) }
|
||||
|
||||
func (b *AbortBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*ApricotAbortBlock) InitRuntime(*runtime.Runtime) {}
|
||||
func (*AbortBlock) InitRuntime(*runtime.Runtime) {}
|
||||
func (*AbortBlock) Txs() []*txs.Tx { return nil }
|
||||
func (b *AbortBlock) Visit(v Visitor) error { return v.AbortBlock(b) }
|
||||
func (*AbortBlock) Initialize(context.Context) error { return nil }
|
||||
|
||||
func (*ApricotAbortBlock) Txs() []*txs.Tx {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ApricotAbortBlock) Visit(v Visitor) error {
|
||||
return v.ApricotAbortBlock(b)
|
||||
}
|
||||
|
||||
// NewApricotAbortBlock is kept for testing purposes only.
|
||||
// Following Banff activation and subsequent code cleanup, Apricot Abort blocks
|
||||
// should be only verified (upon bootstrap), never created anymore
|
||||
func NewApricotAbortBlock(
|
||||
func NewAbortBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
) (*ApricotAbortBlock, error) {
|
||||
blk := &ApricotAbortBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
) (*AbortBlock, error) {
|
||||
blk := &AbortBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
CommonBlock: CommonBlock{PrntID: parentID, Hght: height},
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *BanffAbortBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *ApricotAbortBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package block
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/runtime"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
var _ Block = (*ApricotAtomicBlock)(nil)
|
||||
|
||||
// ApricotAtomicBlock being accepted results in the atomic transaction contained
|
||||
// in the block to be accepted and committed to the chain.
|
||||
type ApricotAtomicBlock struct {
|
||||
CommonBlock `serialize:"true"`
|
||||
Tx *txs.Tx `serialize:"true" json:"tx"`
|
||||
}
|
||||
|
||||
func (b *ApricotAtomicBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
if err := b.Tx.Initialize(txs.Codec); err != nil {
|
||||
return fmt.Errorf("failed to initialize tx: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ApricotAtomicBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
b.Tx.Unsigned.InitRuntime(rt)
|
||||
}
|
||||
|
||||
func (b *ApricotAtomicBlock) Txs() []*txs.Tx {
|
||||
return []*txs.Tx{b.Tx}
|
||||
}
|
||||
|
||||
func (b *ApricotAtomicBlock) Visit(v Visitor) error {
|
||||
return v.ApricotAtomicBlock(b)
|
||||
}
|
||||
|
||||
func NewApricotAtomicBlock(
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
tx *txs.Tx,
|
||||
) (*ApricotAtomicBlock, error) {
|
||||
blk := &ApricotAtomicBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
Tx: tx,
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *ApricotAtomicBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package block
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
lux "github.com/luxfi/utxo"
|
||||
"github.com/luxfi/node/vms/components/verify"
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
func TestNewApricotAtomicBlock(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
parentID := ids.GenerateTestID()
|
||||
height := uint64(1337)
|
||||
tx := &txs.Tx{
|
||||
Unsigned: &txs.ImportTx{
|
||||
BaseTx: txs.BaseTx{
|
||||
BaseTx: lux.BaseTx{
|
||||
Ins: []*lux.TransferableInput{},
|
||||
Outs: []*lux.TransferableOutput{},
|
||||
},
|
||||
},
|
||||
ImportedInputs: []*lux.TransferableInput{},
|
||||
},
|
||||
Creds: []verify.Verifiable{},
|
||||
}
|
||||
require.NoError(tx.Initialize(txs.Codec))
|
||||
|
||||
blk, err := NewApricotAtomicBlock(
|
||||
parentID,
|
||||
height,
|
||||
tx,
|
||||
)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the block and tx are initialized
|
||||
require.NotEmpty(blk.Bytes())
|
||||
require.NotEmpty(blk.Tx.Bytes())
|
||||
require.NotEqual(ids.Empty, blk.Tx.ID())
|
||||
require.Equal(tx.Bytes(), blk.Tx.Bytes())
|
||||
require.Equal(parentID, blk.Parent())
|
||||
require.Equal(height, blk.Height())
|
||||
}
|
||||
@@ -422,7 +422,7 @@ func buildBlock(
|
||||
return nil, fmt.Errorf("could not build tx to reward staker: %w", err)
|
||||
}
|
||||
|
||||
return platformblock.NewBanffProposalBlock(
|
||||
return platformblock.NewProposalBlock(
|
||||
timestamp,
|
||||
parentID,
|
||||
height,
|
||||
@@ -438,7 +438,7 @@ func buildBlock(
|
||||
}
|
||||
|
||||
// Issue a block with as many transactions as possible.
|
||||
return platformblock.NewBanffStandardBlock(
|
||||
return platformblock.NewStandardBlock(
|
||||
timestamp,
|
||||
parentID,
|
||||
height,
|
||||
@@ -446,76 +446,6 @@ func buildBlock(
|
||||
)
|
||||
}
|
||||
|
||||
func packDurangoBlockTxs(
|
||||
ctx context.Context,
|
||||
parentID ids.ID,
|
||||
parentState state.Chain,
|
||||
mempool mempool.Mempool[*txs.Tx],
|
||||
backend *txexecutor.Backend,
|
||||
manager blockexecutor.Manager,
|
||||
timestamp time.Time,
|
||||
pChainHeight uint64,
|
||||
remainingSize int,
|
||||
) ([]*txs.Tx, error) {
|
||||
logger := backend.Runtime.Log.(log.Logger)
|
||||
logger.Debug("packDurangoBlockTxs starting",
|
||||
log.Time("timestamp", timestamp),
|
||||
log.Uint64("pChainHeight", pChainHeight),
|
||||
)
|
||||
stateDiff, err := state.NewDiffOn(parentState)
|
||||
if err != nil {
|
||||
logger.Warn("packDurangoBlockTxs NewDiffOn failed: " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
logger.Debug("packDurangoBlockTxs NewDiffOn succeeded")
|
||||
|
||||
if _, err := txexecutor.AdvanceTimeTo(backend, stateDiff, timestamp); err != nil {
|
||||
logger.Warn("packDurangoBlockTxs AdvanceTimeTo failed: " + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
logger.Debug("packDurangoBlockTxs AdvanceTimeTo succeeded")
|
||||
|
||||
var (
|
||||
blockTxs []*txs.Tx
|
||||
inputs set.Set[ids.ID]
|
||||
feeCalculator = state.PickFeeCalculator(backend.Config, stateDiff)
|
||||
)
|
||||
for {
|
||||
tx, exists := mempool.Peek()
|
||||
if !exists {
|
||||
break
|
||||
}
|
||||
txSize := len(tx.Bytes())
|
||||
if txSize > remainingSize {
|
||||
break
|
||||
}
|
||||
|
||||
shouldAdd, err := executeTx(
|
||||
ctx,
|
||||
parentID,
|
||||
stateDiff,
|
||||
mempool,
|
||||
backend,
|
||||
manager,
|
||||
pChainHeight,
|
||||
&inputs,
|
||||
feeCalculator,
|
||||
tx,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !shouldAdd {
|
||||
continue
|
||||
}
|
||||
|
||||
remainingSize -= txSize
|
||||
blockTxs = append(blockTxs, tx)
|
||||
}
|
||||
|
||||
return blockTxs, nil
|
||||
}
|
||||
|
||||
func packEtnaBlockTxs(
|
||||
ctx context.Context,
|
||||
parentID ids.ID,
|
||||
|
||||
@@ -19,7 +19,7 @@ var (
|
||||
// GenesisCodec allows blocks of larger than usual size to be parsed.
|
||||
// While this gives flexibility in accommodating large genesis blocks
|
||||
// it must not be used to parse new, unverified blocks which instead
|
||||
// must be processed by Codec
|
||||
// must be processed by Codec.
|
||||
GenesisCodec codec.Manager
|
||||
|
||||
Codec codec.Manager
|
||||
@@ -35,12 +35,7 @@ func init() {
|
||||
|
||||
errs := wrappers.Errs{}
|
||||
for _, c := range []linearcodec.Codec{c, gc} {
|
||||
errs.Add(
|
||||
RegisterApricotTypes(c),
|
||||
RegisterBanffTypes(c),
|
||||
RegisterDurangoTypes(c),
|
||||
RegisterEtnaTypes(c),
|
||||
)
|
||||
errs.Add(RegisterBlockTypes(c))
|
||||
}
|
||||
|
||||
Codec = codec.NewDefaultManager()
|
||||
@@ -56,44 +51,21 @@ func init() {
|
||||
}
|
||||
|
||||
// RegisterGenesisType registers a type with the GenesisCodec.
|
||||
// This is used by other packages (like state) to register backward-compatibility types.
|
||||
// This is used by other packages (e.g. state) to register types that are
|
||||
// only ever encountered in genesis bytes.
|
||||
func RegisterGenesisType(val interface{}) error {
|
||||
return genesisLinearCodec.RegisterType(val)
|
||||
}
|
||||
|
||||
// RegisterApricotTypes registers the type information for blocks that were
|
||||
// valid during the Apricot series of upgrades.
|
||||
func RegisterApricotTypes(targetCodec linearcodec.Codec) error {
|
||||
// RegisterBlockTypes registers the canonical block type IDs. There is exactly
|
||||
// one type per block kind: StandardBlock, ProposalBlock, CommitBlock,
|
||||
// AbortBlock. Tx types come from txs.RegisterTypes.
|
||||
func RegisterBlockTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
targetCodec.RegisterType(&ApricotProposalBlock{}),
|
||||
targetCodec.RegisterType(&ApricotAbortBlock{}),
|
||||
targetCodec.RegisterType(&ApricotCommitBlock{}),
|
||||
targetCodec.RegisterType(&ApricotStandardBlock{}),
|
||||
targetCodec.RegisterType(&ApricotAtomicBlock{}),
|
||||
txs.RegisterApricotTypes(targetCodec),
|
||||
txs.RegisterTypes(targetCodec),
|
||||
targetCodec.RegisterType(&ProposalBlock{}),
|
||||
targetCodec.RegisterType(&AbortBlock{}),
|
||||
targetCodec.RegisterType(&CommitBlock{}),
|
||||
targetCodec.RegisterType(&StandardBlock{}),
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterBanffTypes registers the type information for blocks that were valid
|
||||
// during the Banff series of upgrades.
|
||||
func RegisterBanffTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
txs.RegisterBanffTypes(targetCodec),
|
||||
targetCodec.RegisterType(&BanffProposalBlock{}),
|
||||
targetCodec.RegisterType(&BanffAbortBlock{}),
|
||||
targetCodec.RegisterType(&BanffCommitBlock{}),
|
||||
targetCodec.RegisterType(&BanffStandardBlock{}),
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterDurangoTypes registers the type information for blocks that were
|
||||
// valid during the Durango series of upgrades.
|
||||
func RegisterDurangoTypes(targetCodec linearcodec.Codec) error {
|
||||
return txs.RegisterDurangoTypes(targetCodec)
|
||||
}
|
||||
|
||||
// RegisterEtnaTypes registers the type information for blocks that were valid
|
||||
// during the Etna series of upgrades.
|
||||
func RegisterEtnaTypes(targetCodec linearcodec.Codec) error {
|
||||
return txs.RegisterEtnaTypes(targetCodec)
|
||||
}
|
||||
|
||||
@@ -12,81 +12,34 @@ import (
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
var (
|
||||
_ BanffBlock = (*BanffCommitBlock)(nil)
|
||||
_ Block = (*ApricotCommitBlock)(nil)
|
||||
)
|
||||
var _ Block = (*CommitBlock)(nil)
|
||||
|
||||
type BanffCommitBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
ApricotCommitBlock `serialize:"true"`
|
||||
}
|
||||
|
||||
func (b *BanffCommitBlock) Timestamp() time.Time {
|
||||
return time.Unix(int64(b.Time), 0)
|
||||
}
|
||||
|
||||
func (b *BanffCommitBlock) Visit(v Visitor) error {
|
||||
return v.BanffCommitBlock(b)
|
||||
}
|
||||
|
||||
func NewBanffCommitBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
) (*BanffCommitBlock, error) {
|
||||
blk := &BanffCommitBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
ApricotCommitBlock: ApricotCommitBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
},
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
type ApricotCommitBlock struct {
|
||||
// CommitBlock is the canonical P-Chain commit outcome of a ProposalBlock.
|
||||
type CommitBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
CommonBlock `serialize:"true"`
|
||||
}
|
||||
|
||||
func (b *ApricotCommitBlock) initialize(bytes []byte) error {
|
||||
func (b *CommitBlock) Timestamp() time.Time { return time.Unix(int64(b.Time), 0) }
|
||||
|
||||
func (b *CommitBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*ApricotCommitBlock) InitRuntime(*runtime.Runtime) {}
|
||||
func (*CommitBlock) InitRuntime(*runtime.Runtime) {}
|
||||
func (*CommitBlock) Txs() []*txs.Tx { return nil }
|
||||
func (b *CommitBlock) Visit(v Visitor) error { return v.CommitBlock(b) }
|
||||
func (*CommitBlock) Initialize(context.Context) error { return nil }
|
||||
|
||||
func (*ApricotCommitBlock) Txs() []*txs.Tx {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ApricotCommitBlock) Visit(v Visitor) error {
|
||||
return v.ApricotCommitBlock(b)
|
||||
}
|
||||
|
||||
func NewApricotCommitBlock(
|
||||
func NewCommitBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
) (*ApricotCommitBlock, error) {
|
||||
blk := &ApricotCommitBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
) (*CommitBlock, error) {
|
||||
blk := &CommitBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
CommonBlock: CommonBlock{PrntID: parentID, Hght: height},
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *BanffCommitBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *ApricotCommitBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -31,97 +31,21 @@ type acceptor struct {
|
||||
validators validators.Manager
|
||||
}
|
||||
|
||||
func (a *acceptor) BanffAbortBlock(b *block.BanffAbortBlock) error {
|
||||
return a.optionBlock(b, "banff abort")
|
||||
func (a *acceptor) AbortBlock(b *block.AbortBlock) error {
|
||||
return a.optionBlock(b, "abort")
|
||||
}
|
||||
|
||||
func (a *acceptor) BanffCommitBlock(b *block.BanffCommitBlock) error {
|
||||
return a.optionBlock(b, "banff commit")
|
||||
func (a *acceptor) CommitBlock(b *block.CommitBlock) error {
|
||||
return a.optionBlock(b, "commit")
|
||||
}
|
||||
|
||||
func (a *acceptor) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
a.proposalBlock(b, "banff proposal")
|
||||
func (a *acceptor) ProposalBlock(b *block.ProposalBlock) error {
|
||||
a.proposalBlock(b, "proposal")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *acceptor) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
return a.standardBlock(b, "banff standard")
|
||||
}
|
||||
|
||||
func (a *acceptor) ApricotAbortBlock(b *block.ApricotAbortBlock) error {
|
||||
return a.optionBlock(b, "apricot abort")
|
||||
}
|
||||
|
||||
func (a *acceptor) ApricotCommitBlock(b *block.ApricotCommitBlock) error {
|
||||
return a.optionBlock(b, "apricot commit")
|
||||
}
|
||||
|
||||
func (a *acceptor) ApricotProposalBlock(b *block.ApricotProposalBlock) error {
|
||||
a.proposalBlock(b, "apricot proposal")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *acceptor) ApricotStandardBlock(b *block.ApricotStandardBlock) error {
|
||||
return a.standardBlock(b, "apricot standard")
|
||||
}
|
||||
|
||||
func (a *acceptor) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error {
|
||||
blkID := b.ID()
|
||||
defer a.free(blkID)
|
||||
|
||||
blkState, ok := a.getBlockState(blkID)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w %s", errMissingBlockState, blkID)
|
||||
}
|
||||
|
||||
if err := a.commonAccept(blkState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the state to reflect the changes made in [onAcceptState].
|
||||
if err := blkState.onAcceptState.Apply(a.state); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer a.state.Abort()
|
||||
batch, err := a.state.CommitBatch()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to commit VM's database for block %s: %w",
|
||||
blkID,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
// Note that this method writes [batch] to the database.
|
||||
// Apply atomic requests via SharedMemory from context
|
||||
if a.rt.SharedMemory != nil {
|
||||
sharedMemory := a.rt.SharedMemory.(atomic.SharedMemory)
|
||||
if err := sharedMemory.Apply(blkState.atomicRequests, batch); err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to atomically accept tx %s in block %s: %w",
|
||||
b.Tx.ID(),
|
||||
blkID,
|
||||
err,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// If SharedMemory is nil, we must write the batch ourselves
|
||||
if err := batch.Write(); err != nil {
|
||||
return fmt.Errorf("failed to write batch for block %s: %w", blkID, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace(
|
||||
"accepted block",
|
||||
log.String("blockType", "apricot atomic"),
|
||||
log.Stringer("blkID", blkID),
|
||||
log.Uint64("height", b.Height()),
|
||||
log.Stringer("parentID", b.Parent()),
|
||||
log.Stringer("checksum", a.state.Checksum()),
|
||||
)
|
||||
|
||||
return nil
|
||||
func (a *acceptor) StandardBlock(b *block.StandardBlock) error {
|
||||
return a.standardBlock(b, "standard")
|
||||
}
|
||||
|
||||
func (a *acceptor) optionBlock(b block.Block, blockType string) error {
|
||||
|
||||
@@ -42,20 +42,20 @@ type options struct {
|
||||
alternateBlock block.Block
|
||||
}
|
||||
|
||||
func (*options) BanffAbortBlock(*block.BanffAbortBlock) error {
|
||||
func (*options) AbortBlock(*block.AbortBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (*options) BanffCommitBlock(*block.BanffCommitBlock) error {
|
||||
func (*options) CommitBlock(*block.CommitBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (o *options) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
func (o *options) ProposalBlock(b *block.ProposalBlock) error {
|
||||
timestamp := b.Timestamp()
|
||||
blkID := b.ID()
|
||||
nextHeight := b.Height() + 1
|
||||
|
||||
commitBlock, err := block.NewBanffCommitBlock(timestamp, blkID, nextHeight)
|
||||
commitBlock, err := block.NewCommitBlock(timestamp, blkID, nextHeight)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to create commit block: %w",
|
||||
@@ -63,7 +63,7 @@ func (o *options) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
)
|
||||
}
|
||||
|
||||
abortBlock, err := block.NewBanffAbortBlock(timestamp, blkID, nextHeight)
|
||||
abortBlock, err := block.NewAbortBlock(timestamp, blkID, nextHeight)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to create abort block: %w",
|
||||
@@ -95,46 +95,7 @@ func (o *options) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*options) BanffStandardBlock(*block.BanffStandardBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (*options) ApricotAbortBlock(*block.ApricotAbortBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (*options) ApricotCommitBlock(*block.ApricotCommitBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (o *options) ApricotProposalBlock(b *block.ApricotProposalBlock) error {
|
||||
blkID := b.ID()
|
||||
nextHeight := b.Height() + 1
|
||||
|
||||
var err error
|
||||
o.preferredBlock, err = block.NewApricotCommitBlock(blkID, nextHeight)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to create commit block: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
o.alternateBlock, err = block.NewApricotAbortBlock(blkID, nextHeight)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"failed to create abort block: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*options) ApricotStandardBlock(*block.ApricotStandardBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
func (*options) ApricotAtomicBlock(*block.ApricotAtomicBlock) error {
|
||||
func (*options) StandardBlock(*block.StandardBlock) error {
|
||||
return ErrNotOracle
|
||||
}
|
||||
|
||||
|
||||
@@ -20,40 +20,20 @@ type rejector struct {
|
||||
addTxsToMempool bool
|
||||
}
|
||||
|
||||
func (r *rejector) BanffAbortBlock(b *block.BanffAbortBlock) error {
|
||||
return r.rejectBlock(b, "banff abort")
|
||||
func (r *rejector) AbortBlock(b *block.AbortBlock) error {
|
||||
return r.rejectBlock(b, "abort")
|
||||
}
|
||||
|
||||
func (r *rejector) BanffCommitBlock(b *block.BanffCommitBlock) error {
|
||||
return r.rejectBlock(b, "banff commit")
|
||||
func (r *rejector) CommitBlock(b *block.CommitBlock) error {
|
||||
return r.rejectBlock(b, "commit")
|
||||
}
|
||||
|
||||
func (r *rejector) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
return r.rejectBlock(b, "banff proposal")
|
||||
func (r *rejector) ProposalBlock(b *block.ProposalBlock) error {
|
||||
return r.rejectBlock(b, "proposal")
|
||||
}
|
||||
|
||||
func (r *rejector) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
return r.rejectBlock(b, "banff standard")
|
||||
}
|
||||
|
||||
func (r *rejector) ApricotAbortBlock(b *block.ApricotAbortBlock) error {
|
||||
return r.rejectBlock(b, "apricot abort")
|
||||
}
|
||||
|
||||
func (r *rejector) ApricotCommitBlock(b *block.ApricotCommitBlock) error {
|
||||
return r.rejectBlock(b, "apricot commit")
|
||||
}
|
||||
|
||||
func (r *rejector) ApricotProposalBlock(b *block.ApricotProposalBlock) error {
|
||||
return r.rejectBlock(b, "apricot proposal")
|
||||
}
|
||||
|
||||
func (r *rejector) ApricotStandardBlock(b *block.ApricotStandardBlock) error {
|
||||
return r.rejectBlock(b, "apricot standard")
|
||||
}
|
||||
|
||||
func (r *rejector) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error {
|
||||
return r.rejectBlock(b, "apricot atomic")
|
||||
func (r *rejector) StandardBlock(b *block.StandardBlock) error {
|
||||
return r.rejectBlock(b, "standard")
|
||||
}
|
||||
|
||||
func (r *rejector) rejectBlock(b block.Block, blockType string) error {
|
||||
|
||||
@@ -28,9 +28,8 @@ var (
|
||||
_ block.Visitor = (*verifier)(nil)
|
||||
|
||||
ErrConflictingBlockTxs = errors.New("block contains conflicting transactions")
|
||||
ErrStandardBlockWithoutChanges = errors.New("BanffStandardBlock performs no state changes")
|
||||
ErrStandardBlockWithoutChanges = errors.New("StandardBlock performs no state changes")
|
||||
|
||||
errApricotBlockIssuedAfterFork = errors.New("apricot block issued after fork")
|
||||
errIncorrectBlockHeight = errors.New("incorrect block height")
|
||||
errOptionBlockTimestampNotMatchingParent = errors.New("option block proposed timestamp not matching parent block one")
|
||||
)
|
||||
@@ -42,22 +41,22 @@ type verifier struct {
|
||||
pChainHeight uint64
|
||||
}
|
||||
|
||||
func (v *verifier) BanffAbortBlock(b *block.BanffAbortBlock) error {
|
||||
if err := v.banffOptionBlock(b); err != nil {
|
||||
func (v *verifier) AbortBlock(b *block.AbortBlock) error {
|
||||
if err := v.optionBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.abortBlock(b) // Must be the last validity check on the block
|
||||
}
|
||||
|
||||
func (v *verifier) BanffCommitBlock(b *block.BanffCommitBlock) error {
|
||||
if err := v.banffOptionBlock(b); err != nil {
|
||||
func (v *verifier) CommitBlock(b *block.CommitBlock) error {
|
||||
if err := v.optionBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.commitBlock(b) // Must be the last validity check on the block
|
||||
}
|
||||
|
||||
func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
if err := v.banffNonOptionBlock(b); err != nil {
|
||||
func (v *verifier) ProposalBlock(b *block.ProposalBlock) error {
|
||||
if err := v.nonOptionBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -108,8 +107,8 @@ func (v *verifier) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
)
|
||||
}
|
||||
|
||||
func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
if err := v.banffNonOptionBlock(b); err != nil {
|
||||
func (v *verifier) StandardBlock(b *block.StandardBlock) error {
|
||||
if err := v.nonOptionBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -139,89 +138,14 @@ func (v *verifier) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
)
|
||||
}
|
||||
|
||||
func (v *verifier) ApricotAbortBlock(b *block.ApricotAbortBlock) error {
|
||||
if err := v.apricotCommonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.abortBlock(b) // Must be the last validity check on the block
|
||||
}
|
||||
|
||||
func (v *verifier) ApricotCommitBlock(b *block.ApricotCommitBlock) error {
|
||||
if err := v.apricotCommonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.commitBlock(b) // Must be the last validity check on the block
|
||||
}
|
||||
|
||||
func (v *verifier) ApricotProposalBlock(b *block.ApricotProposalBlock) error {
|
||||
if err := v.apricotCommonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parentID := b.Parent()
|
||||
onCommitState, err := state.NewDiff(parentID, v.backend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
onAbortState, err := state.NewDiff(parentID, v.backend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feeCalculator := txfee.NewSimpleCalculator(0)
|
||||
return v.proposalBlock( // Must be the last validity check on the block
|
||||
b,
|
||||
b.Tx,
|
||||
nil,
|
||||
0,
|
||||
onCommitState,
|
||||
onAbortState,
|
||||
feeCalculator,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *verifier) ApricotStandardBlock(b *block.ApricotStandardBlock) error {
|
||||
if err := v.apricotCommonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parentID := b.Parent()
|
||||
onAcceptState, err := state.NewDiff(parentID, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feeCalculator := txfee.NewSimpleCalculator(0)
|
||||
return v.standardBlock( // Must be the last validity check on the block
|
||||
b,
|
||||
b.Transactions,
|
||||
feeCalculator,
|
||||
onAcceptState,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *verifier) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error {
|
||||
// Atomic blocks must go through the standard-block path under
|
||||
// activate-all-implicitly; legacy ApricotAtomicBlocks are never accepted.
|
||||
if err := v.commonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return errApricotBlockIssuedAfterFork
|
||||
}
|
||||
|
||||
func (v *verifier) banffOptionBlock(b block.BanffBlock) error {
|
||||
func (v *verifier) optionBlock(b block.BanffBlock) error {
|
||||
if err := v.commonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Banff option blocks must be uniquely generated from the
|
||||
// BanffProposalBlock. This means that the timestamp must be
|
||||
// standardized to a specific value. Therefore, we require the timestamp to
|
||||
// be equal to the parents timestamp.
|
||||
// Option blocks must be uniquely generated from the parent ProposalBlock.
|
||||
// This means that the timestamp must be standardized to the parent's
|
||||
// timestamp.
|
||||
parentID := b.Parent()
|
||||
parentBlkTime := v.getTimestamp(parentID)
|
||||
blkTime := b.Timestamp()
|
||||
@@ -236,7 +160,7 @@ func (v *verifier) banffOptionBlock(b block.BanffBlock) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *verifier) banffNonOptionBlock(b block.BanffBlock) error {
|
||||
func (v *verifier) nonOptionBlock(b block.BanffBlock) error {
|
||||
if err := v.commonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -257,15 +181,6 @@ func (v *verifier) banffNonOptionBlock(b block.BanffBlock) error {
|
||||
)
|
||||
}
|
||||
|
||||
func (v *verifier) apricotCommonBlock(b block.Block) error {
|
||||
// Apricot blocks are permanently refused under activate-all-implicitly;
|
||||
// every chain-time is post-Banff.
|
||||
if err := v.commonBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
return errApricotBlockIssuedAfterFork
|
||||
}
|
||||
|
||||
func (v *verifier) commonBlock(b block.Block) error {
|
||||
parentID := b.Parent()
|
||||
parent, err := v.GetBlock(parentID)
|
||||
|
||||
@@ -13,20 +13,24 @@ import (
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
var (
|
||||
_ BanffBlock = (*BanffProposalBlock)(nil)
|
||||
_ Block = (*ApricotProposalBlock)(nil)
|
||||
)
|
||||
var _ Block = (*ProposalBlock)(nil)
|
||||
|
||||
type BanffProposalBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
Transactions []*txs.Tx `serialize:"true" json:"txs"`
|
||||
ApricotProposalBlock `serialize:"true"`
|
||||
// ProposalBlock is the canonical P-Chain proposal block. It carries a
|
||||
// per-block timestamp, a single proposal Tx, and a tail of decision Txs that
|
||||
// commit atomically with the proposal outcome.
|
||||
type ProposalBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
Transactions []*txs.Tx `serialize:"true" json:"txs"`
|
||||
CommonBlock `serialize:"true"`
|
||||
Tx *txs.Tx `serialize:"true" json:"tx"`
|
||||
}
|
||||
|
||||
func (b *BanffProposalBlock) initialize(bytes []byte) error {
|
||||
if err := b.ApricotProposalBlock.initialize(bytes); err != nil {
|
||||
return err
|
||||
func (b *ProposalBlock) Timestamp() time.Time { return time.Unix(int64(b.Time), 0) }
|
||||
|
||||
func (b *ProposalBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
if err := b.Tx.Initialize(txs.Codec); err != nil {
|
||||
return fmt.Errorf("failed to initialize tx: %w", err)
|
||||
}
|
||||
for _, tx := range b.Transactions {
|
||||
if err := tx.Initialize(txs.Codec); err != nil {
|
||||
@@ -36,101 +40,36 @@ func (b *BanffProposalBlock) initialize(bytes []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BanffProposalBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
func (b *ProposalBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
b.Tx.Unsigned.InitRuntime(rt)
|
||||
for _, tx := range b.Transactions {
|
||||
tx.Unsigned.InitRuntime(rt)
|
||||
}
|
||||
b.ApricotProposalBlock.InitRuntime(rt)
|
||||
}
|
||||
|
||||
func (b *BanffProposalBlock) Timestamp() time.Time {
|
||||
return time.Unix(int64(b.Time), 0)
|
||||
}
|
||||
|
||||
func (b *BanffProposalBlock) Txs() []*txs.Tx {
|
||||
func (b *ProposalBlock) Txs() []*txs.Tx {
|
||||
l := len(b.Transactions)
|
||||
txs := make([]*txs.Tx, l+1)
|
||||
copy(txs, b.Transactions)
|
||||
txs[l] = b.Tx
|
||||
return txs
|
||||
out := make([]*txs.Tx, l+1)
|
||||
copy(out, b.Transactions)
|
||||
out[l] = b.Tx
|
||||
return out
|
||||
}
|
||||
|
||||
func (b *BanffProposalBlock) Visit(v Visitor) error {
|
||||
return v.BanffProposalBlock(b)
|
||||
}
|
||||
func (b *ProposalBlock) Visit(v Visitor) error { return v.ProposalBlock(b) }
|
||||
func (*ProposalBlock) Initialize(context.Context) error { return nil }
|
||||
|
||||
func NewBanffProposalBlock(
|
||||
func NewProposalBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
proposalTx *txs.Tx,
|
||||
decisionTxs []*txs.Tx,
|
||||
) (*BanffProposalBlock, error) {
|
||||
blk := &BanffProposalBlock{
|
||||
Transactions: decisionTxs,
|
||||
) (*ProposalBlock, error) {
|
||||
blk := &ProposalBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
ApricotProposalBlock: ApricotProposalBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
Tx: proposalTx,
|
||||
},
|
||||
Transactions: decisionTxs,
|
||||
CommonBlock: CommonBlock{PrntID: parentID, Hght: height},
|
||||
Tx: proposalTx,
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
type ApricotProposalBlock struct {
|
||||
CommonBlock `serialize:"true"`
|
||||
Tx *txs.Tx `serialize:"true" json:"tx"`
|
||||
}
|
||||
|
||||
func (b *ApricotProposalBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
if err := b.Tx.Initialize(txs.Codec); err != nil {
|
||||
return fmt.Errorf("failed to initialize tx: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ApricotProposalBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
b.Tx.Unsigned.InitRuntime(rt)
|
||||
}
|
||||
|
||||
func (b *ApricotProposalBlock) Txs() []*txs.Tx {
|
||||
return []*txs.Tx{b.Tx}
|
||||
}
|
||||
|
||||
func (b *ApricotProposalBlock) Visit(v Visitor) error {
|
||||
return v.ApricotProposalBlock(b)
|
||||
}
|
||||
|
||||
// NewApricotProposalBlock is kept for testing purposes only.
|
||||
// Following Banff activation and subsequent code cleanup, Apricot Proposal blocks
|
||||
// should be only verified (upon bootstrap), never created anymore
|
||||
func NewApricotProposalBlock(
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
tx *txs.Tx,
|
||||
) (*ApricotProposalBlock, error) {
|
||||
blk := &ApricotProposalBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
Tx: tx,
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *BanffProposalBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *ApricotProposalBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,49 +13,20 @@ import (
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
)
|
||||
|
||||
var (
|
||||
_ BanffBlock = (*BanffStandardBlock)(nil)
|
||||
_ Block = (*ApricotStandardBlock)(nil)
|
||||
)
|
||||
var _ Block = (*StandardBlock)(nil)
|
||||
|
||||
type BanffStandardBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
ApricotStandardBlock `serialize:"true"`
|
||||
}
|
||||
|
||||
func (b *BanffStandardBlock) Timestamp() time.Time {
|
||||
return time.Unix(int64(b.Time), 0)
|
||||
}
|
||||
|
||||
func (b *BanffStandardBlock) Visit(v Visitor) error {
|
||||
return v.BanffStandardBlock(b)
|
||||
}
|
||||
|
||||
func NewBanffStandardBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
txs []*txs.Tx,
|
||||
) (*BanffStandardBlock, error) {
|
||||
blk := &BanffStandardBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
ApricotStandardBlock: ApricotStandardBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
Transactions: txs,
|
||||
},
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
type ApricotStandardBlock struct {
|
||||
// StandardBlock is the canonical P-Chain standard block. It carries a
|
||||
// per-block timestamp (advance-all-implicitly removed the separate
|
||||
// AdvanceTimeTx flow) and an ordered list of decision txs.
|
||||
type StandardBlock struct {
|
||||
Time uint64 `serialize:"true" json:"time"`
|
||||
CommonBlock `serialize:"true"`
|
||||
Transactions []*txs.Tx `serialize:"true" json:"txs"`
|
||||
}
|
||||
|
||||
func (b *ApricotStandardBlock) initialize(bytes []byte) error {
|
||||
func (b *StandardBlock) Timestamp() time.Time { return time.Unix(int64(b.Time), 0) }
|
||||
|
||||
func (b *StandardBlock) initialize(bytes []byte) error {
|
||||
b.CommonBlock.initialize(bytes)
|
||||
for _, tx := range b.Transactions {
|
||||
if err := tx.Initialize(txs.Codec); err != nil {
|
||||
@@ -65,46 +36,26 @@ func (b *ApricotStandardBlock) initialize(bytes []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ApricotStandardBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
func (b *StandardBlock) InitRuntime(rt *runtime.Runtime) {
|
||||
for _, tx := range b.Transactions {
|
||||
tx.Unsigned.InitRuntime(rt)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *ApricotStandardBlock) Txs() []*txs.Tx {
|
||||
return b.Transactions
|
||||
}
|
||||
func (b *StandardBlock) Txs() []*txs.Tx { return b.Transactions }
|
||||
func (b *StandardBlock) Visit(v Visitor) error { return v.StandardBlock(b) }
|
||||
func (*StandardBlock) Initialize(context.Context) error { return nil }
|
||||
|
||||
func (b *ApricotStandardBlock) Visit(v Visitor) error {
|
||||
return v.ApricotStandardBlock(b)
|
||||
}
|
||||
|
||||
// NewApricotStandardBlock is kept for testing purposes only.
|
||||
// Following Banff activation and subsequent code cleanup, Apricot Standard blocks
|
||||
// should be only verified (upon bootstrap), never created anymore
|
||||
func NewApricotStandardBlock(
|
||||
func NewStandardBlock(
|
||||
timestamp time.Time,
|
||||
parentID ids.ID,
|
||||
height uint64,
|
||||
txs []*txs.Tx,
|
||||
) (*ApricotStandardBlock, error) {
|
||||
blk := &ApricotStandardBlock{
|
||||
CommonBlock: CommonBlock{
|
||||
PrntID: parentID,
|
||||
Hght: height,
|
||||
},
|
||||
) (*StandardBlock, error) {
|
||||
blk := &StandardBlock{
|
||||
Time: uint64(timestamp.Unix()),
|
||||
CommonBlock: CommonBlock{PrntID: parentID, Hght: height},
|
||||
Transactions: txs,
|
||||
}
|
||||
return blk, initialize(blk, &blk.CommonBlock)
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *BanffStandardBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeWithRuntime initializes the block with Runtime
|
||||
func (b *ApricotStandardBlock) Initialize(ctx context.Context) error {
|
||||
// Initialize any context-dependent fields here
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
|
||||
package block
|
||||
|
||||
// Visitor dispatches by the canonical P-Chain block type. Under
|
||||
// activate-all-implicitly there is no legacy Apricot variant — every block
|
||||
// carries a timestamp and is one of the four canonical kinds.
|
||||
type Visitor interface {
|
||||
BanffAbortBlock(*BanffAbortBlock) error
|
||||
BanffCommitBlock(*BanffCommitBlock) error
|
||||
BanffProposalBlock(*BanffProposalBlock) error
|
||||
BanffStandardBlock(*BanffStandardBlock) error
|
||||
|
||||
ApricotAbortBlock(*ApricotAbortBlock) error
|
||||
ApricotCommitBlock(*ApricotCommitBlock) error
|
||||
ApricotProposalBlock(*ApricotProposalBlock) error
|
||||
ApricotStandardBlock(*ApricotStandardBlock) error
|
||||
ApricotAtomicBlock(*ApricotAtomicBlock) error
|
||||
AbortBlock(*AbortBlock) error
|
||||
CommitBlock(*CommitBlock) error
|
||||
ProposalBlock(*ProposalBlock) error
|
||||
StandardBlock(*StandardBlock) error
|
||||
}
|
||||
|
||||
@@ -41,21 +41,21 @@ func newBlockMetrics(registerer metric.Registerer) (*blockMetrics, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) BanffAbortBlock(*block.BanffAbortBlock) error {
|
||||
func (m *blockMetrics) AbortBlock(*block.AbortBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "abort",
|
||||
}).Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) BanffCommitBlock(*block.BanffCommitBlock) error {
|
||||
func (m *blockMetrics) CommitBlock(*block.CommitBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "commit",
|
||||
}).Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
func (m *blockMetrics) ProposalBlock(b *block.ProposalBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "proposal",
|
||||
}).Inc()
|
||||
@@ -67,7 +67,7 @@ func (m *blockMetrics) BanffProposalBlock(b *block.BanffProposalBlock) error {
|
||||
return b.Tx.Unsigned.Visit(m.txMetrics)
|
||||
}
|
||||
|
||||
func (m *blockMetrics) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
func (m *blockMetrics) StandardBlock(b *block.StandardBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "standard",
|
||||
}).Inc()
|
||||
@@ -78,43 +78,3 @@ func (m *blockMetrics) BanffStandardBlock(b *block.BanffStandardBlock) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) ApricotAbortBlock(*block.ApricotAbortBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "abort",
|
||||
}).Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) ApricotCommitBlock(*block.ApricotCommitBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "commit",
|
||||
}).Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) ApricotProposalBlock(b *block.ApricotProposalBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "proposal",
|
||||
}).Inc()
|
||||
return b.Tx.Unsigned.Visit(m.txMetrics)
|
||||
}
|
||||
|
||||
func (m *blockMetrics) ApricotStandardBlock(b *block.ApricotStandardBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "standard",
|
||||
}).Inc()
|
||||
for _, tx := range b.Transactions {
|
||||
if err := tx.Unsigned.Visit(m.txMetrics); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *blockMetrics) ApricotAtomicBlock(b *block.ApricotAtomicBlock) error {
|
||||
m.numBlocks.With(metric.Labels{
|
||||
blkLabel: "atomic",
|
||||
}).Inc()
|
||||
return b.Tx.Unsigned.Visit(m.txMetrics)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
hash "github.com/luxfi/crypto/hash"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/node/upgrade"
|
||||
"github.com/luxfi/node/vms/components/gas"
|
||||
lux "github.com/luxfi/utxo"
|
||||
"github.com/luxfi/node/vms/platformvm/block"
|
||||
@@ -140,7 +141,7 @@ func (s *state) init(genesisBytes []byte) error {
|
||||
// genesisBlock.Accept() because then it'd look for genesisBlock's
|
||||
// non-existent parent)
|
||||
genesisID := hash.ComputeHash256Array(genesisBytes)
|
||||
genesisBlock, err := block.NewApricotCommitBlock(genesisID, 0 /*height*/)
|
||||
genesisBlock, err := block.NewCommitBlock(upgrade.InitiallyActiveTime, genesisID, 0 /*height*/)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+28
-63
@@ -26,7 +26,7 @@ var (
|
||||
// GenesisCodec allows txs of larger than usual size to be parsed.
|
||||
// While this gives flexibility in accommodating large genesis txs
|
||||
// it must not be used to parse new, unverified txs which instead
|
||||
// must be processed by Codec
|
||||
// must be processed by Codec.
|
||||
GenesisCodec codec.Manager
|
||||
)
|
||||
|
||||
@@ -36,23 +36,7 @@ func init() {
|
||||
|
||||
errs := wrappers.Errs{}
|
||||
for _, c := range []linearcodec.Codec{c, gc} {
|
||||
// Order in which type are registered affect the byte representation
|
||||
// generated by marshalling ops. To maintain codec type ordering,
|
||||
// we skip positions for the blocks.
|
||||
c.SkipRegistrations(5)
|
||||
|
||||
errs.Add(
|
||||
RegisterApricotTypes(c),
|
||||
RegisterBanffTypes(c),
|
||||
)
|
||||
|
||||
c.SkipRegistrations(4)
|
||||
|
||||
errs.Add(
|
||||
RegisterDurangoTypes(c),
|
||||
RegisterEtnaTypes(c),
|
||||
RegisterGraniteTypes(c),
|
||||
)
|
||||
errs.Add(RegisterTypes(c))
|
||||
}
|
||||
|
||||
Codec = codec.NewDefaultManager()
|
||||
@@ -66,31 +50,32 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterApricotTypes registers the type information for transactions that
|
||||
// were valid during the Apricot series of upgrades.
|
||||
func RegisterApricotTypes(targetCodec linearcodec.Codec) error {
|
||||
// RegisterTypes registers the canonical platformvm tx codec types in their
|
||||
// canonical order. The ordering is fixed (it determines on-disk type IDs);
|
||||
// new tx types append at the end. SkipRegistrations reserve slots for the
|
||||
// block-level types registered by the block codec so that codec IDs match
|
||||
// up across packages.
|
||||
func RegisterTypes(targetCodec linearcodec.Codec) error {
|
||||
// Reserve 5 slots for the four canonical block types + one historical slot
|
||||
// (atomic block ID) so existing tx type IDs remain stable.
|
||||
targetCodec.SkipRegistrations(5)
|
||||
|
||||
errs := wrappers.Errs{}
|
||||
|
||||
// The secp256k1fx is registered here because this is the same place it is
|
||||
// registered in the XVM. This ensures that the typeIDs match up for utxos
|
||||
// in shared memory.
|
||||
//
|
||||
// MintOutput + MintOperation occupy the slots between TransferInput and
|
||||
// TransferOutput and after TransferOutput respectively. PlatformVM used
|
||||
// to SkipRegistrations(1) on those slots because pre-Granite there was
|
||||
// no native asset minting on P-Chain. With Granite + CreateAssetTx /
|
||||
// OperationTx, P-Chain mints and operates assets natively, so the slots
|
||||
// must be filled by the canonical secp256k1fx types — mirroring XVM
|
||||
// type-ID alignment exactly.
|
||||
errs.Add(targetCodec.RegisterType(&secp256k1fx.TransferInput{}))
|
||||
errs.Add(targetCodec.RegisterType(&secp256k1fx.MintOutput{}))
|
||||
errs.Add(targetCodec.RegisterType(&secp256k1fx.TransferOutput{}))
|
||||
errs.Add(targetCodec.RegisterType(&secp256k1fx.MintOperation{}))
|
||||
// secp256k1fx types are registered here because this matches the
|
||||
// XVM registration order — utxos crossed in shared memory must
|
||||
// have identical codec IDs across chains.
|
||||
errs.Add(
|
||||
targetCodec.RegisterType(&secp256k1fx.TransferInput{}),
|
||||
targetCodec.RegisterType(&secp256k1fx.MintOutput{}),
|
||||
targetCodec.RegisterType(&secp256k1fx.TransferOutput{}),
|
||||
targetCodec.RegisterType(&secp256k1fx.MintOperation{}),
|
||||
|
||||
targetCodec.RegisterType(&secp256k1fx.Credential{}),
|
||||
targetCodec.RegisterType(&secp256k1fx.Input{}),
|
||||
targetCodec.RegisterType(&secp256k1fx.OutputOwners{}),
|
||||
|
||||
// Canonical tx kinds (block-1 era).
|
||||
targetCodec.RegisterType(&AddValidatorTx{}),
|
||||
targetCodec.RegisterType(&AddChainValidatorTx{}),
|
||||
targetCodec.RegisterType(&AddDelegatorTx{}),
|
||||
@@ -104,13 +89,11 @@ func RegisterApricotTypes(targetCodec linearcodec.Codec) error {
|
||||
targetCodec.RegisterType(&stakeable.LockIn{}),
|
||||
targetCodec.RegisterType(&stakeable.LockOut{}),
|
||||
)
|
||||
return errs.Err
|
||||
}
|
||||
|
||||
// RegisterBanffTypes registers the type information for transactions that were
|
||||
// valid during the Banff series of upgrades.
|
||||
func RegisterBanffTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
// Skip 4 historical slots so subsequent types keep their ID.
|
||||
targetCodec.SkipRegistrations(4)
|
||||
|
||||
errs.Add(
|
||||
targetCodec.RegisterType(&RemoveChainValidatorTx{}),
|
||||
targetCodec.RegisterType(&TransformChainTx{}),
|
||||
targetCodec.RegisterType(&AddPermissionlessValidatorTx{}),
|
||||
@@ -118,41 +101,23 @@ func RegisterBanffTypes(targetCodec linearcodec.Codec) error {
|
||||
|
||||
targetCodec.RegisterType(&signer.Empty{}),
|
||||
targetCodec.RegisterType(&signer.ProofOfPossession{}),
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterDurangoTypes registers the type information for transactions that
|
||||
// were valid during the Durango series of upgrades.
|
||||
func RegisterDurangoTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
targetCodec.RegisterType(&TransferChainOwnershipTx{}),
|
||||
targetCodec.RegisterType(&BaseTx{}),
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterEtnaTypes registers the type information for transactions that
|
||||
// were valid during the Etna series of upgrades.
|
||||
func RegisterEtnaTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
targetCodec.RegisterType(&ConvertNetworkToL1Tx{}),
|
||||
targetCodec.RegisterType(&RegisterL1ValidatorTx{}),
|
||||
targetCodec.RegisterType(&SetL1ValidatorWeightTx{}),
|
||||
targetCodec.RegisterType(&IncreaseL1ValidatorBalanceTx{}),
|
||||
targetCodec.RegisterType(&DisableL1ValidatorTx{}),
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterGraniteTypes registers the type information for transactions that
|
||||
// are valid during the Granite series of upgrades.
|
||||
func RegisterGraniteTypes(targetCodec linearcodec.Codec) error {
|
||||
return errors.Join(
|
||||
targetCodec.RegisterType(&SlashValidatorTx{}),
|
||||
|
||||
// P-only primary network — assets that historically lived on the
|
||||
// X-Chain are first-class P-Chain UTXO operations. Type IDs go at
|
||||
// the end of the existing registration order so they cannot
|
||||
// collide with any subnet / validator tx.
|
||||
// X-Chain are first-class P-Chain UTXO operations.
|
||||
targetCodec.RegisterType(&CreateAssetTx{}),
|
||||
targetCodec.RegisterType(&OperationTx{}),
|
||||
)
|
||||
|
||||
return errors.Join(errs.Err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user