mirror of https://github.com/poanetwork/gecko.git
Updated Export Tx to support change addresses
This commit is contained in:
parent
42b5b137d4
commit
a7f2a887ca
|
@ -4,12 +4,9 @@
|
||||||
package avm
|
package avm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/chains/atomic"
|
"github.com/ava-labs/gecko/chains/atomic"
|
||||||
"github.com/ava-labs/gecko/database"
|
"github.com/ava-labs/gecko/database"
|
||||||
"github.com/ava-labs/gecko/database/versiondb"
|
"github.com/ava-labs/gecko/database/versiondb"
|
||||||
"github.com/ava-labs/gecko/ids"
|
|
||||||
"github.com/ava-labs/gecko/snow"
|
"github.com/ava-labs/gecko/snow"
|
||||||
"github.com/ava-labs/gecko/snow/choices"
|
"github.com/ava-labs/gecko/snow/choices"
|
||||||
"github.com/ava-labs/gecko/vms/components/ava"
|
"github.com/ava-labs/gecko/vms/components/ava"
|
||||||
|
@ -17,47 +14,22 @@ import (
|
||||||
"github.com/ava-labs/gecko/vms/components/verify"
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExportTx is a transaction that exports an asset to another blockchain.
|
// ExportTx is the basis of all transactions.
|
||||||
type ExportTx struct {
|
type ExportTx struct {
|
||||||
BaseTx `serialize:"true"`
|
BaseTx `serialize:"true"`
|
||||||
|
|
||||||
Outs []*ava.TransferableOutput `serialize:"true"` // The outputs of this transaction
|
ExportOuts []*ava.TransferableOutput `serialize:"true"` // The outputs this transaction is sending to the other chain
|
||||||
Ins []*ava.TransferableInput `serialize:"true"` // The inputs to this transaction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputUTXOs track which UTXOs this transaction is consuming.
|
|
||||||
func (t *ExportTx) InputUTXOs() []*ava.UTXOID {
|
|
||||||
utxos := t.BaseTx.InputUTXOs()
|
|
||||||
for _, in := range t.Ins {
|
|
||||||
utxos = append(utxos, &in.UTXOID)
|
|
||||||
}
|
|
||||||
return utxos
|
|
||||||
}
|
|
||||||
|
|
||||||
// AssetIDs returns the IDs of the assets this transaction depends on
|
|
||||||
func (t *ExportTx) AssetIDs() ids.Set {
|
|
||||||
assets := t.BaseTx.AssetIDs()
|
|
||||||
for _, in := range t.Ins {
|
|
||||||
assets.Add(in.AssetID())
|
|
||||||
}
|
|
||||||
return assets
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNoExportInputs = errors.New("no export inputs")
|
|
||||||
)
|
|
||||||
|
|
||||||
// SyntacticVerify that this transaction is well-formed.
|
// SyntacticVerify that this transaction is well-formed.
|
||||||
func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int) error {
|
func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, _ int) error {
|
||||||
switch {
|
switch {
|
||||||
case t == nil:
|
case t == nil:
|
||||||
return errNilTx
|
return errNilTx
|
||||||
case len(t.Ins) == 0:
|
case t.NetID != ctx.NetworkID:
|
||||||
return errNoExportInputs
|
return errWrongNetworkID
|
||||||
}
|
case !t.BCID.Equals(ctx.ChainID):
|
||||||
|
return errWrongChainID
|
||||||
if err := t.BaseTx.SyntacticVerify(ctx, c, numFxs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fc := ava.NewFlowChecker()
|
fc := ava.NewFlowChecker()
|
||||||
|
@ -71,6 +43,16 @@ func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
return errOutputsNotSorted
|
return errOutputsNotSorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, out := range t.ExportOuts {
|
||||||
|
if err := out.Verify(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fc.Produce(out.AssetID(), out.Output().Amount())
|
||||||
|
}
|
||||||
|
if !ava.IsSortedTransferableOutputs(t.ExportOuts, c) {
|
||||||
|
return errOutputsNotSorted
|
||||||
|
}
|
||||||
|
|
||||||
for _, in := range t.Ins {
|
for _, in := range t.Ins {
|
||||||
if err := in.Verify(); err != nil {
|
if err := in.Verify(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -83,18 +65,17 @@ func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
|
|
||||||
// TODO: Add the Tx fee to the produced side
|
// TODO: Add the Tx fee to the produced side
|
||||||
|
|
||||||
return fc.Verify()
|
if err := fc.Verify(); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
// SemanticVerify that this transaction is well-formed.
|
|
||||||
func (t *ExportTx) SemanticVerify(vm *VM, uTx *UniqueTx, creds []verify.Verifiable) error {
|
|
||||||
if err := t.BaseTx.SemanticVerify(vm, uTx, creds); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := len(t.BaseTx.Ins)
|
return t.Metadata.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemanticVerify that this transaction is valid to be spent.
|
||||||
|
func (t *ExportTx) SemanticVerify(vm *VM, uTx *UniqueTx, creds []verify.Verifiable) error {
|
||||||
for i, in := range t.Ins {
|
for i, in := range t.Ins {
|
||||||
cred := creds[i+offset]
|
cred := creds[i]
|
||||||
|
|
||||||
fxIndex, err := vm.getFx(cred)
|
fxIndex, err := vm.getFx(cred)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -112,9 +93,6 @@ func (t *ExportTx) SemanticVerify(vm *VM, uTx *UniqueTx, creds []verify.Verifiab
|
||||||
if !utxoAssetID.Equals(inAssetID) {
|
if !utxoAssetID.Equals(inAssetID) {
|
||||||
return errAssetIDMismatch
|
return errAssetIDMismatch
|
||||||
}
|
}
|
||||||
if !utxoAssetID.Equals(vm.ava) {
|
|
||||||
return errWrongAssetID
|
|
||||||
}
|
|
||||||
|
|
||||||
if !vm.verifyFxUsage(fxIndex, inAssetID) {
|
if !vm.verifyFxUsage(fxIndex, inAssetID) {
|
||||||
return errIncompatibleFx
|
return errIncompatibleFx
|
||||||
|
@ -124,6 +102,13 @@ func (t *ExportTx) SemanticVerify(vm *VM, uTx *UniqueTx, creds []verify.Verifiab
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, out := range t.ExportOuts {
|
||||||
|
if !out.AssetID().Equals(vm.ava) {
|
||||||
|
return errWrongAssetID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +122,11 @@ func (t *ExportTx) ExecuteWithSideEffects(vm *VM, batch database.Batch) error {
|
||||||
vsmDB := versiondb.New(smDB)
|
vsmDB := versiondb.New(smDB)
|
||||||
|
|
||||||
state := ava.NewPrefixedState(vsmDB, vm.codec)
|
state := ava.NewPrefixedState(vsmDB, vm.codec)
|
||||||
for i, out := range t.Outs {
|
for i, out := range t.ExportOuts {
|
||||||
utxo := &ava.UTXO{
|
utxo := &ava.UTXO{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: txID,
|
TxID: txID,
|
||||||
OutputIndex: uint32(len(t.BaseTx.Outs) + i),
|
OutputIndex: uint32(len(t.Outs) + i),
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: out.AssetID()},
|
Asset: ava.Asset{ID: out.AssetID()},
|
||||||
Out: out.Out,
|
Out: out.Out,
|
||||||
|
|
|
@ -31,10 +31,6 @@ func TestExportTxSerialization(t *testing.T) {
|
||||||
0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc,
|
0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc,
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa,
|
0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||||
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
||||||
// number of base outs:
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
// number of base inputs:
|
|
||||||
0x00, 0x00, 0x00, 0x00,
|
|
||||||
// number of outs:
|
// number of outs:
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
// number of inputs:
|
// number of inputs:
|
||||||
|
@ -60,18 +56,18 @@ func TestExportTxSerialization(t *testing.T) {
|
||||||
0x00, 0x00, 0x00, 0x01,
|
0x00, 0x00, 0x00, 0x01,
|
||||||
// sig index[0]:
|
// sig index[0]:
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
// number of exported outs:
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := &Tx{UnsignedTx: &ExportTx{
|
tx := &Tx{UnsignedTx: &ExportTx{BaseTx: BaseTx{
|
||||||
BaseTx: BaseTx{
|
NetID: 2,
|
||||||
NetID: 2,
|
BCID: ids.NewID([32]byte{
|
||||||
BCID: ids.NewID([32]byte{
|
0xff, 0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xee,
|
||||||
0xff, 0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xee,
|
0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc,
|
||||||
0xdd, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, 0xcc,
|
0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||||
0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa,
|
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
||||||
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
}),
|
||||||
}),
|
|
||||||
},
|
|
||||||
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
UTXOID: ava.UTXOID{TxID: ids.NewID([32]byte{
|
UTXOID: ava.UTXOID{TxID: ids.NewID([32]byte{
|
||||||
0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
|
0x0f, 0x2f, 0x4f, 0x6f, 0x8e, 0xae, 0xce, 0xee,
|
||||||
|
@ -90,7 +86,7 @@ func TestExportTxSerialization(t *testing.T) {
|
||||||
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
}}
|
}}}
|
||||||
|
|
||||||
c := codec.NewDefault()
|
c := codec.NewDefault()
|
||||||
c.RegisterType(&BaseTx{})
|
c.RegisterType(&BaseTx{})
|
||||||
|
@ -161,19 +157,19 @@ func TestIssueExportTx(t *testing.T) {
|
||||||
BaseTx: BaseTx{
|
BaseTx: BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
|
UTXOID: ava.UTXOID{
|
||||||
|
TxID: avaID,
|
||||||
|
OutputIndex: 1,
|
||||||
|
},
|
||||||
|
Asset: ava.Asset{ID: avaID},
|
||||||
|
In: &secp256k1fx.TransferInput{
|
||||||
|
Amt: 50000,
|
||||||
|
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
ExportOuts: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
UTXOID: ava.UTXOID{
|
|
||||||
TxID: avaID,
|
|
||||||
OutputIndex: 1,
|
|
||||||
},
|
|
||||||
Asset: ava.Asset{ID: avaID},
|
|
||||||
In: &secp256k1fx.TransferInput{
|
|
||||||
Amt: 50000,
|
|
||||||
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
|
||||||
Asset: ava.Asset{ID: avaID},
|
Asset: ava.Asset{ID: avaID},
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Amt: 50000,
|
Amt: 50000,
|
||||||
|
@ -297,19 +293,19 @@ func TestClearForceAcceptedExportTx(t *testing.T) {
|
||||||
BaseTx: BaseTx{
|
BaseTx: BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
|
UTXOID: ava.UTXOID{
|
||||||
|
TxID: avaID,
|
||||||
|
OutputIndex: 1,
|
||||||
|
},
|
||||||
|
Asset: ava.Asset{ID: avaID},
|
||||||
|
In: &secp256k1fx.TransferInput{
|
||||||
|
Amt: 50000,
|
||||||
|
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
ExportOuts: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
UTXOID: ava.UTXOID{
|
|
||||||
TxID: avaID,
|
|
||||||
OutputIndex: 1,
|
|
||||||
},
|
|
||||||
Asset: ava.Asset{ID: avaID},
|
|
||||||
In: &secp256k1fx.TransferInput{
|
|
||||||
Amt: 50000,
|
|
||||||
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
|
||||||
Asset: ava.Asset{ID: avaID},
|
Asset: ava.Asset{ID: avaID},
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Amt: 50000,
|
Amt: 50000,
|
||||||
|
|
Loading…
Reference in New Issue