Files
node/vms/platformvm/state/state_txs.go
T
zeekayandHanzo Dev c44cc2289f platformvm builds GREEN off the codec: executor fold + full consumer flip
vms/platformvm/... build + vet PASS with pcodecs/txs.Codec gone from the VM.

Executor semantics (standard_tx_executor):
- registerOwnSet(): shared primitive — per-validator state.L1Validator with
  native owner blobs (txs.MarshalOwner/UnmarshalOwner, no codec), active-set
  capacity check, EndAccumulatedFee=balance+accruedFees, SetNetToL1Conversion
  manager-authority recording (byte-for-byte legacy tail).
- ConvertNetworkTx: promote endomorphism (owner-authorized, folds old
  ConvertNetworkToL1Tx), gated by security.Mode.Manager.
- CreateNetworkTx: base (AddNet/SetNetOwner) + sovereign path registers own set.
- Deleted CreateSovereignL1Tx + ConvertNetworkToL1Tx.
- txs.UnmarshalOwner added: canonical owner marshal/unmarshal pair, no codec.

All ~13 txs.Visitor impls carry ConvertNetworkTx; gossip/block Parse(b) codec-free;
wallet/network/primary off txs.Codec.

KNOWN GAP (pending design decision, NOT silently green): CreateNetworkTx reads
tx.Chains() only to derive managerChainID — it does NOT create the genesis
chains (no AddChain). Atomic-spawn-with-chains vs decomplect-to-CreateChainTx is
the open call. 17 codec-era _test.go parked as .bak for follow-up rewrite.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 14:25:08 -07:00

144 lines
3.5 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package state
import (
"fmt"
"github.com/luxfi/database"
"github.com/luxfi/database/linkeddb"
"github.com/luxfi/database/prefixdb"
"github.com/luxfi/ids"
lux "github.com/luxfi/utxo"
"github.com/luxfi/node/vms/platformvm/status"
"github.com/luxfi/node/vms/platformvm/txs"
)
func (s *state) GetTx(txID ids.ID) (*txs.Tx, status.Status, error) {
if tx, exists := s.addedTxs[txID]; exists {
return tx.tx, tx.status, nil
}
if tx, cached := s.txCache.Get(txID); cached {
if tx == nil {
return nil, status.Unknown, database.ErrNotFound
}
return tx.tx, tx.status, nil
}
txBytes, err := s.txDB.Get(txID[:])
if err == database.ErrNotFound {
s.txCache.Put(txID, nil)
return nil, status.Unknown, database.ErrNotFound
}
if err != nil {
return nil, status.Unknown, err
}
stx, err := parseTxStatus(txBytes)
if err != nil {
return nil, status.Unknown, err
}
tx, err := txs.Parse(stx.Tx)
if err != nil {
return nil, status.Unknown, err
}
ptx := &txAndStatus{
tx: tx,
status: stx.Status,
}
s.txCache.Put(txID, ptx)
return ptx.tx, ptx.status, nil
}
func (s *state) AddTx(tx *txs.Tx, status status.Status) {
s.addedTxs[tx.ID()] = &txAndStatus{
tx: tx,
status: status,
}
}
func (s *state) GetRewardUTXOs(txID ids.ID) ([]*lux.UTXO, error) {
if utxos, exists := s.addedRewardUTXOs[txID]; exists {
return utxos, nil
}
if utxos, cached := s.rewardUTXOsCache.Get(txID); cached {
return utxos, nil
}
rawTxDB := prefixdb.New(txID[:], s.rewardUTXODB)
txDB := linkeddb.NewDefault(rawTxDB)
it := txDB.NewIterator()
defer it.Release()
utxos := []*lux.UTXO(nil)
for it.Next() {
utxo, err := lux.ParseUTXO(it.Value())
if err != nil {
return nil, err
}
utxos = append(utxos, utxo)
}
if err := it.Error(); err != nil {
return nil, err
}
s.rewardUTXOsCache.Put(txID, utxos)
return utxos, nil
}
func (s *state) AddRewardUTXO(txID ids.ID, utxo *lux.UTXO) {
s.addedRewardUTXOs[txID] = append(s.addedRewardUTXOs[txID], utxo)
}
func (s *state) writeTXs() error {
for txID, txStatus := range s.addedTxs {
stx := txBytesAndStatus{
Tx: txStatus.tx.Bytes(),
Status: txStatus.status,
}
// We serialize the [txBytesAndStatus] envelope natively (see
// statewire.go). The embedded tx keeps its own self-delimiting
// signed bytes so its TxID is preserved on re-parse.
txBytes, err := marshalTxStatus(stx)
if err != nil {
return fmt.Errorf("failed to serialize tx: %w", err)
}
delete(s.addedTxs, txID)
// Note: Evict is used rather than Put here because stx may end up
// referencing additional data (because of shared byte slices) that
// would not be properly accounted for in the cache sizing.
s.txCache.Evict(txID)
if err := s.txDB.Put(txID[:], txBytes); err != nil {
return fmt.Errorf("failed to add tx: %w", err)
}
}
return nil
}
func (s *state) writeRewardUTXOs() error {
for txID, utxos := range s.addedRewardUTXOs {
delete(s.addedRewardUTXOs, txID)
s.rewardUTXOsCache.Put(txID, utxos)
rawTxDB := prefixdb.New(txID[:], s.rewardUTXODB)
txDB := linkeddb.NewDefault(rawTxDB)
for _, utxo := range utxos {
utxoBytes, err := utxo.WireBytes()
if err != nil {
return fmt.Errorf("failed to serialize reward UTXO: %w", err)
}
utxoID := utxo.InputID()
if err := txDB.Put(utxoID[:], utxoBytes); err != nil {
return fmt.Errorf("failed to add reward UTXO: %w", err)
}
}
}
return nil
}