mirror of
https://github.com/luxfi/proto.git
synced 2026-10-30 15:21:09 +00:00
- safemath.Add64/Mul64 → Add/Mul (Go generics; same wire/bounds
behaviour, fewer per-width copies). Sweep across p/{reward,utxo,txs}
and the x-side test helpers.
- lux.SortTransferableOutputs / SyntacticVerifier UTXO/Output helpers:
drop the threaded Codec arg; sort key is now Bytes()+assetID, no
codec roundtrip per compare. Callers in p/utxo/handler.go,
p/txs/{add_*,base_tx,builder,executor/*}, p/state, and
x/txs/executor/syntactic_verifier follow.
- stakeable.LockOut: implement Bytes() returning
0xFF || BE(Locktime) || inner.Bytes(). 0xFF marker keeps locked
outputs sorted strictly AFTER unlocked fxs primitives, preserving
the legacy ordering invariant the SyntacticVerify expects.
- Update test helpers in p/block/{builder,executor}, p/network, p/txs
to construct outputs without the codec arg and rely on the new sort.
116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package txs
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/math/set"
|
|
"github.com/luxfi/runtime"
|
|
lux "github.com/luxfi/utxo"
|
|
"github.com/luxfi/utxo/secp256k1fx"
|
|
)
|
|
|
|
var (
|
|
_ UnsignedTx = (*BaseTx)(nil)
|
|
|
|
ErrNilTx = errors.New("tx is nil")
|
|
|
|
errOutputsNotSorted = errors.New("outputs not sorted")
|
|
errInputsNotSortedUnique = errors.New("inputs not sorted and unique")
|
|
)
|
|
|
|
// BaseTx contains fields common to many transaction types. It should be
|
|
// embedded in transaction implementations.
|
|
type BaseTx struct {
|
|
lux.BaseTx `serialize:"true"`
|
|
|
|
// true iff this transaction has already passed syntactic verification
|
|
SyntacticallyVerified bool `serialize:"-" json:"-"`
|
|
|
|
unsignedBytes []byte // Unsigned byte representation of this data
|
|
}
|
|
|
|
func (tx *BaseTx) SetBytes(unsignedBytes []byte) {
|
|
tx.unsignedBytes = unsignedBytes
|
|
}
|
|
|
|
func (tx *BaseTx) Bytes() []byte {
|
|
return tx.unsignedBytes
|
|
}
|
|
|
|
func (tx *BaseTx) InputIDs() set.Set[ids.ID] {
|
|
inputIDs := set.NewSet[ids.ID](len(tx.Ins))
|
|
for _, in := range tx.Ins {
|
|
inputIDs.Add(in.InputID())
|
|
}
|
|
return inputIDs
|
|
}
|
|
|
|
func (tx *BaseTx) Outputs() []*lux.TransferableOutput {
|
|
return tx.Outs
|
|
}
|
|
|
|
// InitRuntime sets the FxID fields in the inputs and outputs of this [BaseTx]. Also
|
|
// sets the [ctx] to the given [vm.ctx] so that the addresses can be json
|
|
// marshalled into human readable format
|
|
func (tx *BaseTx) InitRuntime(rt *runtime.Runtime) {
|
|
for _, in := range tx.BaseTx.Ins {
|
|
in.FxID = secp256k1fx.ID
|
|
}
|
|
for _, out := range tx.BaseTx.Outs {
|
|
out.FxID = secp256k1fx.ID
|
|
out.InitRuntime(rt)
|
|
}
|
|
}
|
|
|
|
// InitializeContext is a no-op. Runtime is passed explicitly.
|
|
func (tx *BaseTx) InitializeContext(ctx context.Context) error {
|
|
return nil
|
|
}
|
|
|
|
// SyntacticVerify returns nil iff this tx is well formed
|
|
func (tx *BaseTx) SyntacticVerify(rt *runtime.Runtime) error {
|
|
switch {
|
|
case tx == nil:
|
|
return ErrNilTx
|
|
case tx.SyntacticallyVerified: // already passed syntactic verification
|
|
return nil
|
|
}
|
|
if err := tx.BaseTx.Verify(rt); err != nil {
|
|
return fmt.Errorf("metadata failed verification: %w", err)
|
|
}
|
|
for _, out := range tx.Outs {
|
|
if err := out.Verify(); err != nil {
|
|
return fmt.Errorf("output failed verification: %w", err)
|
|
}
|
|
}
|
|
for _, in := range tx.Ins {
|
|
if err := in.Verify(); err != nil {
|
|
return fmt.Errorf("input failed verification: %w", err)
|
|
}
|
|
}
|
|
switch {
|
|
case !lux.IsSortedTransferableOutputs(tx.Outs):
|
|
return errOutputsNotSorted
|
|
case !isSortedAndUniqueByCompare(tx.Ins):
|
|
return errInputsNotSortedUnique
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (tx *BaseTx) Visit(visitor Visitor) error {
|
|
return visitor.BaseTx(tx)
|
|
}
|
|
|
|
// InitializeWithContext initializes the transaction with consensus context
|
|
func (tx *BaseTx) InitializeWithContext(ctx context.Context) error {
|
|
// Initialize any context-dependent fields here
|
|
return nil
|
|
}
|