mirror of https://github.com/poanetwork/gecko.git
wip
This commit is contained in:
parent
a6a92510af
commit
93ed25f878
|
@ -21,6 +21,9 @@ const (
|
||||||
|
|
||||||
// SECP256K1SKLen is the number of bytes in a secp2561k private key
|
// SECP256K1SKLen is the number of bytes in a secp2561k private key
|
||||||
SECP256K1SKLen = 32
|
SECP256K1SKLen = 32
|
||||||
|
|
||||||
|
// SECP256K1PKLen is the number of bytes in a secp2561k public key
|
||||||
|
SECP256K1PKLen = 33
|
||||||
)
|
)
|
||||||
|
|
||||||
// FactorySECP256K1 ...
|
// FactorySECP256K1 ...
|
||||||
|
|
|
@ -27,6 +27,10 @@ const (
|
||||||
// SECP256K1RSKLen is the number of bytes in a secp2561k recoverable private
|
// SECP256K1RSKLen is the number of bytes in a secp2561k recoverable private
|
||||||
// key
|
// key
|
||||||
SECP256K1RSKLen = 32
|
SECP256K1RSKLen = 32
|
||||||
|
|
||||||
|
// SECP256K1RPKLen is the number of bytes in a secp2561k recoverable public
|
||||||
|
// key
|
||||||
|
SECP256K1RPKLen = 33
|
||||||
)
|
)
|
||||||
|
|
||||||
// FactorySECP256K1R ...
|
// FactorySECP256K1R ...
|
||||||
|
|
|
@ -31,10 +31,10 @@ var (
|
||||||
type BaseTx struct {
|
type BaseTx struct {
|
||||||
ava.Metadata
|
ava.Metadata
|
||||||
|
|
||||||
NetID uint32 `serialize:"true"` // ID of the network this chain lives on
|
NetID uint32 `serialize:"true"` // ID of the network this chain lives on
|
||||||
BCID ids.ID `serialize:"true"` // ID of the chain on which this transaction exists (prevents replay attacks)
|
BCID ids.ID `serialize:"true"` // ID of the chain on which this transaction exists (prevents replay attacks)
|
||||||
Outs []*TransferableOutput `serialize:"true"` // The outputs of this transaction
|
Outs []*ava.TransferableOutput `serialize:"true"` // The outputs of this transaction
|
||||||
Ins []*TransferableInput `serialize:"true"` // The inputs to this transaction
|
Ins []*ava.TransferableInput `serialize:"true"` // The inputs to this transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkID is the ID of the network on which this transaction exists
|
// NetworkID is the ID of the network on which this transaction exists
|
||||||
|
@ -45,11 +45,11 @@ func (t *BaseTx) ChainID() ids.ID { return t.BCID }
|
||||||
|
|
||||||
// Outputs track which outputs this transaction is producing. The returned array
|
// Outputs track which outputs this transaction is producing. The returned array
|
||||||
// should not be modified.
|
// should not be modified.
|
||||||
func (t *BaseTx) Outputs() []*TransferableOutput { return t.Outs }
|
func (t *BaseTx) Outputs() []*ava.TransferableOutput { return t.Outs }
|
||||||
|
|
||||||
// Inputs track which UTXOs this transaction is consuming. The returned array
|
// Inputs track which UTXOs this transaction is consuming. The returned array
|
||||||
// should not be modified.
|
// should not be modified.
|
||||||
func (t *BaseTx) Inputs() []*TransferableInput { return t.Ins }
|
func (t *BaseTx) Inputs() []*ava.TransferableInput { return t.Ins }
|
||||||
|
|
||||||
// InputUTXOs track which UTXOs this transaction is consuming.
|
// InputUTXOs track which UTXOs this transaction is consuming.
|
||||||
func (t *BaseTx) InputUTXOs() []*ava.UTXOID {
|
func (t *BaseTx) InputUTXOs() []*ava.UTXOID {
|
||||||
|
@ -104,7 +104,7 @@ func (t *BaseTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, _ int) error
|
||||||
}
|
}
|
||||||
fc.Produce(out.AssetID(), out.Output().Amount())
|
fc.Produce(out.AssetID(), out.Output().Amount())
|
||||||
}
|
}
|
||||||
if !IsSortedTransferableOutputs(t.Outs, c) {
|
if !ava.IsSortedTransferableOutputs(t.Outs, c) {
|
||||||
return errOutputsNotSorted
|
return errOutputsNotSorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ func (t *BaseTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, _ int) error
|
||||||
}
|
}
|
||||||
fc.Consume(in.AssetID(), in.Input().Amount())
|
fc.Consume(in.AssetID(), in.Input().Amount())
|
||||||
}
|
}
|
||||||
if !isSortedAndUniqueTransferableInputs(t.Ins) {
|
if !ava.IsSortedAndUniqueTransferableInputs(t.Ins) {
|
||||||
return errInputsNotSortedUnique
|
return errInputsNotSortedUnique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -93,64 +93,60 @@ func TestCreateAssetTxSerialization(t *testing.T) {
|
||||||
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,
|
||||||
}),
|
}),
|
||||||
Outs: []*TransferableOutput{
|
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
&TransferableOutput{
|
Asset: ava.Asset{
|
||||||
Asset: ava.Asset{
|
ID: ids.NewID([32]byte{
|
||||||
ID: ids.NewID([32]byte{
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
}),
|
||||||
}),
|
},
|
||||||
},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: 12345,
|
||||||
Amt: 12345,
|
Locktime: 54321,
|
||||||
Locktime: 54321,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{
|
||||||
Addrs: []ids.ShortID{
|
ids.NewShortID([20]byte{
|
||||||
ids.NewShortID([20]byte{
|
0x51, 0x02, 0x5c, 0x61, 0xfb, 0xcf, 0xc0, 0x78,
|
||||||
0x51, 0x02, 0x5c, 0x61, 0xfb, 0xcf, 0xc0, 0x78,
|
0xf6, 0x93, 0x34, 0xf8, 0x34, 0xbe, 0x6d, 0xd2,
|
||||||
0xf6, 0x93, 0x34, 0xf8, 0x34, 0xbe, 0x6d, 0xd2,
|
0x6d, 0x55, 0xa9, 0x55,
|
||||||
0x6d, 0x55, 0xa9, 0x55,
|
}),
|
||||||
}),
|
ids.NewShortID([20]byte{
|
||||||
ids.NewShortID([20]byte{
|
0xc3, 0x34, 0x41, 0x28, 0xe0, 0x60, 0x12, 0x8e,
|
||||||
0xc3, 0x34, 0x41, 0x28, 0xe0, 0x60, 0x12, 0x8e,
|
0xde, 0x35, 0x23, 0xa2, 0x4a, 0x46, 0x1c, 0x89,
|
||||||
0xde, 0x35, 0x23, 0xa2, 0x4a, 0x46, 0x1c, 0x89,
|
0x43, 0xab, 0x08, 0x59,
|
||||||
0x43, 0xab, 0x08, 0x59,
|
}),
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: ids.NewID([32]byte{
|
||||||
TxID: ids.NewID([32]byte{
|
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
|
||||||
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
|
0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
|
||||||
0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
|
0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
|
||||||
0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
|
0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
|
||||||
0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
|
}),
|
||||||
}),
|
OutputIndex: 5,
|
||||||
OutputIndex: 5,
|
},
|
||||||
},
|
Asset: ava.Asset{
|
||||||
Asset: ava.Asset{
|
ID: ids.NewID([32]byte{
|
||||||
ID: ids.NewID([32]byte{
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
}),
|
||||||
}),
|
},
|
||||||
},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 123456789,
|
||||||
Amt: 123456789,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{3, 7},
|
||||||
SigIndices: []uint32{3, 7},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
},
|
||||||
Name: "Volatility Index",
|
Name: "Volatility Index",
|
||||||
Symbol: "VIX",
|
Symbol: "VIX",
|
||||||
|
|
|
@ -21,8 +21,8 @@ import (
|
||||||
type ExportTx struct {
|
type ExportTx struct {
|
||||||
BaseTx `serialize:"true"`
|
BaseTx `serialize:"true"`
|
||||||
|
|
||||||
Outs []*TransferableOutput `serialize:"true"` // The outputs of this transaction
|
Outs []*ava.TransferableOutput `serialize:"true"` // The outputs of this transaction
|
||||||
Ins []*TransferableInput `serialize:"true"` // The inputs to this transaction
|
Ins []*ava.TransferableInput `serialize:"true"` // The inputs to this transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputUTXOs track which UTXOs this transaction is consuming.
|
// InputUTXOs track which UTXOs this transaction is consuming.
|
||||||
|
@ -67,7 +67,7 @@ func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
}
|
}
|
||||||
fc.Produce(out.AssetID(), out.Output().Amount())
|
fc.Produce(out.AssetID(), out.Output().Amount())
|
||||||
}
|
}
|
||||||
if !IsSortedTransferableOutputs(t.Outs, c) {
|
if !ava.IsSortedTransferableOutputs(t.Outs, c) {
|
||||||
return errOutputsNotSorted
|
return errOutputsNotSorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ func (t *ExportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
}
|
}
|
||||||
fc.Consume(in.AssetID(), in.Input().Amount())
|
fc.Consume(in.AssetID(), in.Input().Amount())
|
||||||
}
|
}
|
||||||
if !isSortedAndUniqueTransferableInputs(t.Ins) {
|
if !ava.IsSortedAndUniqueTransferableInputs(t.Ins) {
|
||||||
return errInputsNotSortedUnique
|
return errInputsNotSortedUnique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ func TestExportTxSerialization(t *testing.T) {
|
||||||
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&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,
|
||||||
0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
|
0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
|
||||||
|
@ -156,7 +156,7 @@ func TestIssueExportTx(t *testing.T) {
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: genesisTx.ID(),
|
TxID: genesisTx.ID(),
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
|
@ -167,7 +167,7 @@ func TestIssueExportTx(t *testing.T) {
|
||||||
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
Outs: []*TransferableOutput{&TransferableOutput{
|
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Amt: 50000,
|
Amt: 50000,
|
||||||
|
@ -287,7 +287,7 @@ func TestClearForceAcceptedExportTx(t *testing.T) {
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: genesisTx.ID(),
|
TxID: genesisTx.ID(),
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
|
@ -298,7 +298,7 @@ func TestClearForceAcceptedExportTx(t *testing.T) {
|
||||||
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
Outs: []*TransferableOutput{&TransferableOutput{
|
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Amt: 50000,
|
Amt: 50000,
|
||||||
|
|
|
@ -5,7 +5,6 @@ package avm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
"github.com/ava-labs/gecko/vms/components/verify"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type parsedFx struct {
|
type parsedFx struct {
|
||||||
|
@ -32,16 +31,6 @@ type Fx interface {
|
||||||
VerifyOperation(tx interface{}, utxos, ins, creds, outs []interface{}) error
|
VerifyOperation(tx interface{}, utxos, ins, creds, outs []interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// FxTransferable is the interface a feature extension must provide to transfer
|
|
||||||
// value between features extensions.
|
|
||||||
type FxTransferable interface {
|
|
||||||
verify.Verifiable
|
|
||||||
|
|
||||||
// Amount returns how much value this output consumes of the asset in its
|
|
||||||
// transaction.
|
|
||||||
Amount() uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// FxAddressable is the interface a feature extension must provide to be able to
|
// FxAddressable is the interface a feature extension must provide to be able to
|
||||||
// be tracked as a part of the utxo set for a set of addresses
|
// be tracked as a part of the utxo set for a set of addresses
|
||||||
type FxAddressable interface {
|
type FxAddressable interface {
|
||||||
|
|
|
@ -17,16 +17,12 @@ import (
|
||||||
"github.com/ava-labs/gecko/vms/components/verify"
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errNilUTXOID = errors.New("nil utxo ID is not valid")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImportTx is a transaction that imports an asset from another blockchain.
|
// ImportTx is a transaction that imports an asset from another blockchain.
|
||||||
type ImportTx struct {
|
type ImportTx struct {
|
||||||
BaseTx `serialize:"true"`
|
BaseTx `serialize:"true"`
|
||||||
|
|
||||||
Outs []*TransferableOutput `serialize:"true"` // The outputs of this transaction
|
Outs []*ava.TransferableOutput `serialize:"true"` // The outputs of this transaction
|
||||||
Ins []*TransferableInput `serialize:"true"` // The inputs to this transaction
|
Ins []*ava.TransferableInput `serialize:"true"` // The inputs to this transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputUTXOs track which UTXOs this transaction is consuming.
|
// InputUTXOs track which UTXOs this transaction is consuming.
|
||||||
|
@ -91,7 +87,7 @@ func (t *ImportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
}
|
}
|
||||||
fc.Produce(out.AssetID(), out.Output().Amount())
|
fc.Produce(out.AssetID(), out.Output().Amount())
|
||||||
}
|
}
|
||||||
if !IsSortedTransferableOutputs(t.Outs, c) {
|
if !ava.IsSortedTransferableOutputs(t.Outs, c) {
|
||||||
return errOutputsNotSorted
|
return errOutputsNotSorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +97,7 @@ func (t *ImportTx) SyntacticVerify(ctx *snow.Context, c codec.Codec, numFxs int)
|
||||||
}
|
}
|
||||||
fc.Consume(in.AssetID(), in.Input().Amount())
|
fc.Consume(in.AssetID(), in.Input().Amount())
|
||||||
}
|
}
|
||||||
if !isSortedAndUniqueTransferableInputs(t.Ins) {
|
if !ava.IsSortedAndUniqueTransferableInputs(t.Ins) {
|
||||||
return errInputsNotSortedUnique
|
return errInputsNotSortedUnique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ func TestImportTxSerialization(t *testing.T) {
|
||||||
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&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,
|
||||||
0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
|
0x0d, 0x2d, 0x4d, 0x6d, 0x8c, 0xac, 0xcc, 0xec,
|
||||||
|
@ -165,7 +165,7 @@ func TestIssueImportTx(t *testing.T) {
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
UTXOID: utxoID,
|
UTXOID: utxoID,
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
In: &secp256k1fx.TransferInput{
|
In: &secp256k1fx.TransferInput{
|
||||||
|
@ -306,7 +306,7 @@ func TestForceAcceptImportTx(t *testing.T) {
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
},
|
},
|
||||||
Ins: []*TransferableInput{&TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
UTXOID: utxoID,
|
UTXOID: utxoID,
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
In: &secp256k1fx.TransferInput{
|
In: &secp256k1fx.TransferInput{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
"github.com/ava-labs/gecko/utils/formatting"
|
"github.com/ava-labs/gecko/utils/formatting"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/ava"
|
||||||
"github.com/ava-labs/gecko/vms/components/codec"
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
"github.com/ava-labs/gecko/vms/components/verify"
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
@ -52,14 +53,12 @@ func TestInitialStateVerifyNilOutput(t *testing.T) {
|
||||||
|
|
||||||
func TestInitialStateVerifyInvalidOutput(t *testing.T) {
|
func TestInitialStateVerifyInvalidOutput(t *testing.T) {
|
||||||
c := codec.NewDefault()
|
c := codec.NewDefault()
|
||||||
c.RegisterType(&testVerifiable{})
|
c.RegisterType(&ava.TestVerifiable{})
|
||||||
numFxs := 1
|
numFxs := 1
|
||||||
|
|
||||||
is := InitialState{
|
is := InitialState{
|
||||||
FxID: 0,
|
FxID: 0,
|
||||||
Outs: []verify.Verifiable{
|
Outs: []verify.Verifiable{&ava.TestVerifiable{Err: errors.New("")}},
|
||||||
&testVerifiable{err: errors.New("")},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if err := is.Verify(c, numFxs); err == nil {
|
if err := is.Verify(c, numFxs); err == nil {
|
||||||
t.Fatalf("Should have errored due to an invalid output")
|
t.Fatalf("Should have errored due to an invalid output")
|
||||||
|
@ -68,14 +67,14 @@ func TestInitialStateVerifyInvalidOutput(t *testing.T) {
|
||||||
|
|
||||||
func TestInitialStateVerifyUnsortedOutputs(t *testing.T) {
|
func TestInitialStateVerifyUnsortedOutputs(t *testing.T) {
|
||||||
c := codec.NewDefault()
|
c := codec.NewDefault()
|
||||||
c.RegisterType(&TestTransferable{})
|
c.RegisterType(&ava.TestTransferable{})
|
||||||
numFxs := 1
|
numFxs := 1
|
||||||
|
|
||||||
is := InitialState{
|
is := InitialState{
|
||||||
FxID: 0,
|
FxID: 0,
|
||||||
Outs: []verify.Verifiable{
|
Outs: []verify.Verifiable{
|
||||||
&TestTransferable{Val: 1},
|
&ava.TestTransferable{Val: 1},
|
||||||
&TestTransferable{Val: 0},
|
&ava.TestTransferable{Val: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := is.Verify(c, numFxs); err == nil {
|
if err := is.Verify(c, numFxs); err == nil {
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestOperableInputVerifyNilFx(t *testing.T) {
|
||||||
func TestOperableInputVerify(t *testing.T) {
|
func TestOperableInputVerify(t *testing.T) {
|
||||||
oi := &OperableInput{
|
oi := &OperableInput{
|
||||||
UTXOID: ava.UTXOID{TxID: ids.Empty},
|
UTXOID: ava.UTXOID{TxID: ids.Empty},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
}
|
}
|
||||||
if err := oi.Verify(); err != nil {
|
if err := oi.Verify(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -44,28 +44,28 @@ func TestOperableInputSorting(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
&OperableInput{
|
&OperableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.NewID([32]byte{1}),
|
TxID: ids.NewID([32]byte{1}),
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
&OperableInput{
|
&OperableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
&OperableInput{
|
&OperableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.NewID([32]byte{1}),
|
TxID: ids.NewID([32]byte{1}),
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if isSortedAndUniqueOperableInputs(ins) {
|
if isSortedAndUniqueOperableInputs(ins) {
|
||||||
|
@ -98,7 +98,7 @@ func TestOperableInputSorting(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
})
|
})
|
||||||
if isSortedAndUniqueOperableInputs(ins) {
|
if isSortedAndUniqueOperableInputs(ins) {
|
||||||
t.Fatalf("Shouldn't be unique")
|
t.Fatalf("Shouldn't be unique")
|
||||||
|
|
|
@ -53,14 +53,14 @@ func TestOperationVerifyInputsNotSorted(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
&OperableInput{
|
&OperableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@ func TestOperationVerifyInputsNotSorted(t *testing.T) {
|
||||||
|
|
||||||
func TestOperationVerifyOutputsNotSorted(t *testing.T) {
|
func TestOperationVerifyOutputsNotSorted(t *testing.T) {
|
||||||
c := codec.NewDefault()
|
c := codec.NewDefault()
|
||||||
c.RegisterType(&TestTransferable{})
|
c.RegisterType(&ava.TestTransferable{})
|
||||||
|
|
||||||
op := &Operation{
|
op := &Operation{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: ava.Asset{ID: ids.Empty},
|
||||||
Outs: []verify.Verifiable{
|
Outs: []verify.Verifiable{
|
||||||
&TestTransferable{Val: 1},
|
&ava.TestTransferable{Val: 1},
|
||||||
&TestTransferable{Val: 0},
|
&ava.TestTransferable{Val: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := op.Verify(c); err == nil {
|
if err := op.Verify(c); err == nil {
|
||||||
|
@ -90,7 +90,7 @@ func TestOperationVerify(t *testing.T) {
|
||||||
op := &Operation{
|
op := &Operation{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: ava.Asset{ID: ids.Empty},
|
||||||
Outs: []verify.Verifiable{
|
Outs: []verify.Verifiable{
|
||||||
&testVerifiable{},
|
&ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := op.Verify(c); err != nil {
|
if err := op.Verify(c); err != nil {
|
||||||
|
@ -100,7 +100,7 @@ func TestOperationVerify(t *testing.T) {
|
||||||
|
|
||||||
func TestOperationSorting(t *testing.T) {
|
func TestOperationSorting(t *testing.T) {
|
||||||
c := codec.NewDefault()
|
c := codec.NewDefault()
|
||||||
c.RegisterType(&testVerifiable{})
|
c.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
ops := []*Operation{
|
ops := []*Operation{
|
||||||
&Operation{
|
&Operation{
|
||||||
|
@ -111,7 +111,7 @@ func TestOperationSorting(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -123,7 +123,7 @@ func TestOperationSorting(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -143,7 +143,7 @@ func TestOperationSorting(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestPrefixedSetsAndGets(t *testing.T) {
|
||||||
vm := GenesisVM(t)
|
vm := GenesisVM(t)
|
||||||
state := vm.state
|
state := vm.state
|
||||||
|
|
||||||
vm.codec.RegisterType(&testVerifiable{})
|
vm.codec.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
utxo := &ava.UTXO{
|
utxo := &ava.UTXO{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
|
@ -27,29 +27,27 @@ func TestPrefixedSetsAndGets(t *testing.T) {
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: ava.Asset{ID: ids.Empty},
|
||||||
Out: &testVerifiable{},
|
Out: &ava.TestVerifiable{},
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := &Tx{UnsignedTx: &BaseTx{
|
tx := &Tx{UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: ids.Empty,
|
||||||
TxID: ids.Empty,
|
OutputIndex: 0,
|
||||||
OutputIndex: 0,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: asset},
|
||||||
Asset: ava.Asset{ID: asset},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 20 * units.KiloAva,
|
||||||
Amt: 20 * units.KiloAva,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
unsignedBytes, err := vm.codec.Marshal(tx.UnsignedTx)
|
unsignedBytes, err := vm.codec.Marshal(tx.UnsignedTx)
|
||||||
|
@ -115,7 +113,7 @@ func TestPrefixedFundingNoAddresses(t *testing.T) {
|
||||||
vm := GenesisVM(t)
|
vm := GenesisVM(t)
|
||||||
state := vm.state
|
state := vm.state
|
||||||
|
|
||||||
vm.codec.RegisterType(&testVerifiable{})
|
vm.codec.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
utxo := &ava.UTXO{
|
utxo := &ava.UTXO{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
|
@ -123,7 +121,7 @@ func TestPrefixedFundingNoAddresses(t *testing.T) {
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: ava.Asset{ID: ids.Empty},
|
||||||
Out: &testVerifiable{},
|
Out: &ava.TestVerifiable{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.FundUTXO(utxo); err != nil {
|
if err := state.FundUTXO(utxo); err != nil {
|
||||||
|
|
|
@ -219,7 +219,7 @@ func (service *Service) GetBalance(r *http.Request, args *GetBalanceArgs, reply
|
||||||
|
|
||||||
for _, utxo := range utxos {
|
for _, utxo := range utxos {
|
||||||
if utxo.AssetID().Equals(assetID) {
|
if utxo.AssetID().Equals(assetID) {
|
||||||
transferable, ok := utxo.Out.(FxTransferable)
|
transferable, ok := utxo.Out.(ava.Transferable)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -601,7 +601,7 @@ func (service *Service) Send(r *http.Request, args *SendArgs, reply *SendReply)
|
||||||
amountSpent := uint64(0)
|
amountSpent := uint64(0)
|
||||||
time := service.vm.clock.Unix()
|
time := service.vm.clock.Unix()
|
||||||
|
|
||||||
ins := []*TransferableInput{}
|
ins := []*ava.TransferableInput{}
|
||||||
keys := [][]*crypto.PrivateKeySECP256K1R{}
|
keys := [][]*crypto.PrivateKeySECP256K1R{}
|
||||||
for _, utxo := range utxos {
|
for _, utxo := range utxos {
|
||||||
if !utxo.AssetID().Equals(assetID) {
|
if !utxo.AssetID().Equals(assetID) {
|
||||||
|
@ -611,7 +611,7 @@ func (service *Service) Send(r *http.Request, args *SendArgs, reply *SendReply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
input, ok := inputIntf.(FxTransferable)
|
input, ok := inputIntf.(ava.Transferable)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -621,7 +621,7 @@ func (service *Service) Send(r *http.Request, args *SendArgs, reply *SendReply)
|
||||||
}
|
}
|
||||||
amountSpent = spent
|
amountSpent = spent
|
||||||
|
|
||||||
in := &TransferableInput{
|
in := &ava.TransferableInput{
|
||||||
UTXOID: utxo.UTXOID,
|
UTXOID: utxo.UTXOID,
|
||||||
Asset: ava.Asset{ID: assetID},
|
Asset: ava.Asset{ID: assetID},
|
||||||
In: input,
|
In: input,
|
||||||
|
@ -641,38 +641,34 @@ func (service *Service) Send(r *http.Request, args *SendArgs, reply *SendReply)
|
||||||
|
|
||||||
SortTransferableInputsWithSigners(ins, keys)
|
SortTransferableInputsWithSigners(ins, keys)
|
||||||
|
|
||||||
outs := []*TransferableOutput{
|
outs := []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
&TransferableOutput{
|
Asset: ava.Asset{ID: assetID},
|
||||||
Asset: ava.Asset{ID: assetID},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: uint64(args.Amount),
|
||||||
Amt: uint64(args.Amount),
|
Locktime: 0,
|
||||||
Locktime: 0,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{to},
|
||||||
Addrs: []ids.ShortID{to},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}}
|
||||||
|
|
||||||
if amountSpent > uint64(args.Amount) {
|
if amountSpent > uint64(args.Amount) {
|
||||||
changeAddr := kc.Keys[0].PublicKey().Address()
|
changeAddr := kc.Keys[0].PublicKey().Address()
|
||||||
outs = append(outs,
|
outs = append(outs, &ava.TransferableOutput{
|
||||||
&TransferableOutput{
|
Asset: ava.Asset{ID: assetID},
|
||||||
Asset: ava.Asset{ID: assetID},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: amountSpent - uint64(args.Amount),
|
||||||
Amt: amountSpent - uint64(args.Amount),
|
Locktime: 0,
|
||||||
Locktime: 0,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{changeAddr},
|
||||||
Addrs: []ids.ShortID{changeAddr},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
SortTransferableOutputs(outs, service.vm.codec)
|
ava.SortTransferableOutputs(outs, service.vm.codec)
|
||||||
|
|
||||||
tx := Tx{
|
tx := Tx{
|
||||||
UnsignedTx: &BaseTx{
|
UnsignedTx: &BaseTx{
|
||||||
|
@ -719,7 +715,7 @@ func (service *Service) Send(r *http.Request, args *SendArgs, reply *SendReply)
|
||||||
}
|
}
|
||||||
|
|
||||||
type innerSortTransferableInputsWithSigners struct {
|
type innerSortTransferableInputsWithSigners struct {
|
||||||
ins []*TransferableInput
|
ins []*ava.TransferableInput
|
||||||
signers [][]*crypto.PrivateKeySECP256K1R
|
signers [][]*crypto.PrivateKeySECP256K1R
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,13 +740,13 @@ func (ins *innerSortTransferableInputsWithSigners) Swap(i, j int) {
|
||||||
|
|
||||||
// SortTransferableInputsWithSigners sorts the inputs and signers based on the
|
// SortTransferableInputsWithSigners sorts the inputs and signers based on the
|
||||||
// input's utxo ID
|
// input's utxo ID
|
||||||
func SortTransferableInputsWithSigners(ins []*TransferableInput, signers [][]*crypto.PrivateKeySECP256K1R) {
|
func SortTransferableInputsWithSigners(ins []*ava.TransferableInput, signers [][]*crypto.PrivateKeySECP256K1R) {
|
||||||
sort.Sort(&innerSortTransferableInputsWithSigners{ins: ins, signers: signers})
|
sort.Sort(&innerSortTransferableInputsWithSigners{ins: ins, signers: signers})
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSortedAndUniqueTransferableInputsWithSigners returns true if the inputs are
|
// IsSortedAndUniqueTransferableInputsWithSigners returns true if the inputs are
|
||||||
// sorted and unique
|
// sorted and unique
|
||||||
func IsSortedAndUniqueTransferableInputsWithSigners(ins []*TransferableInput, signers [][]*crypto.PrivateKeySECP256K1R) bool {
|
func IsSortedAndUniqueTransferableInputsWithSigners(ins []*ava.TransferableInput, signers [][]*crypto.PrivateKeySECP256K1R) bool {
|
||||||
return utils.IsSortedAndUnique(&innerSortTransferableInputsWithSigners{ins: ins, signers: signers})
|
return utils.IsSortedAndUnique(&innerSortTransferableInputsWithSigners{ins: ins, signers: signers})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ func TestStateUTXOs(t *testing.T) {
|
||||||
vm := GenesisVM(t)
|
vm := GenesisVM(t)
|
||||||
state := vm.state.state
|
state := vm.state.state
|
||||||
|
|
||||||
vm.codec.RegisterType(&testVerifiable{})
|
vm.codec.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
if _, err := state.UTXO(ids.Empty); err == nil {
|
if _, err := state.UTXO(ids.Empty); err == nil {
|
||||||
t.Fatalf("Should have errored when reading utxo")
|
t.Fatalf("Should have errored when reading utxo")
|
||||||
|
@ -187,7 +187,7 @@ func TestStateUTXOs(t *testing.T) {
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: ava.Asset{ID: ids.Empty},
|
||||||
Out: &testVerifiable{},
|
Out: &ava.TestVerifiable{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.SetUTXO(ids.Empty, utxo); err != nil {
|
if err := state.SetUTXO(ids.Empty, utxo); err != nil {
|
||||||
|
@ -245,7 +245,7 @@ func TestStateTXs(t *testing.T) {
|
||||||
vm := GenesisVM(t)
|
vm := GenesisVM(t)
|
||||||
state := vm.state.state
|
state := vm.state.state
|
||||||
|
|
||||||
vm.codec.RegisterType(&TestTransferable{})
|
vm.codec.RegisterType(&ava.TestTransferable{})
|
||||||
|
|
||||||
if _, err := state.Tx(ids.Empty); err == nil {
|
if _, err := state.Tx(ids.Empty); err == nil {
|
||||||
t.Fatalf("Should have errored when reading tx")
|
t.Fatalf("Should have errored when reading tx")
|
||||||
|
@ -254,23 +254,21 @@ func TestStateTXs(t *testing.T) {
|
||||||
tx := &Tx{UnsignedTx: &BaseTx{
|
tx := &Tx{UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: ids.Empty,
|
||||||
TxID: ids.Empty,
|
OutputIndex: 0,
|
||||||
OutputIndex: 0,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: asset},
|
||||||
Asset: ava.Asset{ID: asset},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 20 * units.KiloAva,
|
||||||
Amt: 20 * units.KiloAva,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
unsignedBytes, err := vm.codec.Marshal(tx.UnsignedTx)
|
unsignedBytes, err := vm.codec.Marshal(tx.UnsignedTx)
|
||||||
|
|
|
@ -26,8 +26,8 @@ type UnsignedTx interface {
|
||||||
|
|
||||||
NetworkID() uint32
|
NetworkID() uint32
|
||||||
ChainID() ids.ID
|
ChainID() ids.ID
|
||||||
Outputs() []*TransferableOutput
|
Outputs() []*ava.TransferableOutput
|
||||||
Inputs() []*TransferableInput
|
Inputs() []*ava.TransferableInput
|
||||||
|
|
||||||
AssetIDs() ids.Set
|
AssetIDs() ids.Set
|
||||||
InputUTXOs() []*ava.UTXOID
|
InputUTXOs() []*ava.UTXOID
|
||||||
|
|
|
@ -44,33 +44,29 @@ func TestTxInvalidCredential(t *testing.T) {
|
||||||
c.RegisterType(&secp256k1fx.MintInput{})
|
c.RegisterType(&secp256k1fx.MintInput{})
|
||||||
c.RegisterType(&secp256k1fx.TransferInput{})
|
c.RegisterType(&secp256k1fx.TransferInput{})
|
||||||
c.RegisterType(&secp256k1fx.Credential{})
|
c.RegisterType(&secp256k1fx.Credential{})
|
||||||
c.RegisterType(&testVerifiable{})
|
c.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
tx := &Tx{
|
tx := &Tx{
|
||||||
UnsignedTx: &BaseTx{
|
UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: ids.Empty,
|
||||||
TxID: ids.Empty,
|
OutputIndex: 0,
|
||||||
OutputIndex: 0,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: asset},
|
||||||
Asset: ava.Asset{ID: asset},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 20 * units.KiloAva,
|
||||||
Amt: 20 * units.KiloAva,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
|
||||||
Creds: []verify.Verifiable{
|
|
||||||
&testVerifiable{err: errUnneededAddress},
|
|
||||||
},
|
},
|
||||||
|
Creds: []verify.Verifiable{&ava.TestVerifiable{Err: errUnneededAddress}},
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := c.Marshal(tx)
|
b, err := c.Marshal(tx)
|
||||||
|
@ -94,14 +90,14 @@ func TestTxInvalidUnsignedTx(t *testing.T) {
|
||||||
c.RegisterType(&secp256k1fx.MintInput{})
|
c.RegisterType(&secp256k1fx.MintInput{})
|
||||||
c.RegisterType(&secp256k1fx.TransferInput{})
|
c.RegisterType(&secp256k1fx.TransferInput{})
|
||||||
c.RegisterType(&secp256k1fx.Credential{})
|
c.RegisterType(&secp256k1fx.Credential{})
|
||||||
c.RegisterType(&testVerifiable{})
|
c.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
tx := &Tx{
|
tx := &Tx{
|
||||||
UnsignedTx: &BaseTx{
|
UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{
|
||||||
&TransferableInput{
|
&ava.TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
|
@ -116,7 +112,7 @@ func TestTxInvalidUnsignedTx(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&TransferableInput{
|
&ava.TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: ava.UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
|
@ -134,8 +130,8 @@ func TestTxInvalidUnsignedTx(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Creds: []verify.Verifiable{
|
Creds: []verify.Verifiable{
|
||||||
&testVerifiable{},
|
&ava.TestVerifiable{},
|
||||||
&testVerifiable{},
|
&ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,27 +156,25 @@ func TestTxInvalidNumberOfCredentials(t *testing.T) {
|
||||||
c.RegisterType(&secp256k1fx.MintInput{})
|
c.RegisterType(&secp256k1fx.MintInput{})
|
||||||
c.RegisterType(&secp256k1fx.TransferInput{})
|
c.RegisterType(&secp256k1fx.TransferInput{})
|
||||||
c.RegisterType(&secp256k1fx.Credential{})
|
c.RegisterType(&secp256k1fx.Credential{})
|
||||||
c.RegisterType(&testVerifiable{})
|
c.RegisterType(&ava.TestVerifiable{})
|
||||||
|
|
||||||
tx := &Tx{
|
tx := &Tx{
|
||||||
UnsignedTx: &OperationTx{
|
UnsignedTx: &OperationTx{
|
||||||
BaseTx: BaseTx{
|
BaseTx: BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{TxID: ids.Empty, OutputIndex: 0},
|
||||||
UTXOID: ava.UTXOID{TxID: ids.Empty, OutputIndex: 0},
|
Asset: ava.Asset{ID: asset},
|
||||||
Asset: ava.Asset{ID: asset},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 20 * units.KiloAva,
|
||||||
Amt: 20 * units.KiloAva,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
},
|
||||||
Ops: []*Operation{
|
Ops: []*Operation{
|
||||||
&Operation{
|
&Operation{
|
||||||
|
@ -191,15 +185,13 @@ func TestTxInvalidNumberOfCredentials(t *testing.T) {
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
In: &testVerifiable{},
|
In: &ava.TestVerifiable{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Creds: []verify.Verifiable{
|
Creds: []verify.Verifiable{&ava.TestVerifiable{}},
|
||||||
&testVerifiable{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := c.Marshal(tx)
|
b, err := c.Marshal(tx)
|
||||||
|
|
|
@ -3,20 +3,10 @@
|
||||||
|
|
||||||
package avm
|
package avm
|
||||||
|
|
||||||
type testVerifiable struct{ err error }
|
import "github.com/ava-labs/gecko/vms/components/ava"
|
||||||
|
|
||||||
func (v *testVerifiable) Verify() error { return v.err }
|
|
||||||
|
|
||||||
type TestTransferable struct {
|
|
||||||
testVerifiable
|
|
||||||
|
|
||||||
Val uint64 `serialize:"true"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TestTransferable) Amount() uint64 { return t.Val }
|
|
||||||
|
|
||||||
type testAddressable struct {
|
type testAddressable struct {
|
||||||
TestTransferable `serialize:"true"`
|
ava.TestTransferable `serialize:"true"`
|
||||||
|
|
||||||
Addrs [][]byte `serialize:"true"`
|
Addrs [][]byte `serialize:"true"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,7 +317,7 @@ func TestTxSerialization(t *testing.T) {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
addr := key.PublicKey().Address()
|
addr := key.PublicKey().Address()
|
||||||
|
|
||||||
unsignedTx.Outs = append(unsignedTx.Outs, &TransferableOutput{
|
unsignedTx.Outs = append(unsignedTx.Outs, &ava.TransferableOutput{
|
||||||
Asset: ava.Asset{ID: asset},
|
Asset: ava.Asset{ID: asset},
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Amt: 20 * units.KiloAva,
|
Amt: 20 * units.KiloAva,
|
||||||
|
@ -444,23 +444,21 @@ func TestIssueTx(t *testing.T) {
|
||||||
newTx := &Tx{UnsignedTx: &BaseTx{
|
newTx := &Tx{UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: genesisTx.ID(),
|
||||||
TxID: genesisTx.ID(),
|
OutputIndex: 1,
|
||||||
OutputIndex: 1,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 50000,
|
||||||
Amt: 50000,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
unsignedBytes, err := vm.codec.Marshal(&newTx.UnsignedTx)
|
unsignedBytes, err := vm.codec.Marshal(&newTx.UnsignedTx)
|
||||||
|
@ -575,35 +573,31 @@ func TestIssueDependentTx(t *testing.T) {
|
||||||
firstTx := &Tx{UnsignedTx: &BaseTx{
|
firstTx := &Tx{UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: genesisTx.ID(),
|
||||||
TxID: genesisTx.ID(),
|
OutputIndex: 1,
|
||||||
OutputIndex: 1,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 50000,
|
||||||
Amt: 50000,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
Outs: []*TransferableOutput{
|
Outs: []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
&TransferableOutput{
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: 50000,
|
||||||
Amt: 50000,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{key.PublicKey().Address()},
|
||||||
Addrs: []ids.ShortID{key.PublicKey().Address()},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
unsignedBytes, err := vm.codec.Marshal(&firstTx.UnsignedTx)
|
unsignedBytes, err := vm.codec.Marshal(&firstTx.UnsignedTx)
|
||||||
|
@ -638,23 +632,21 @@ func TestIssueDependentTx(t *testing.T) {
|
||||||
secondTx := &Tx{UnsignedTx: &BaseTx{
|
secondTx := &Tx{UnsignedTx: &BaseTx{
|
||||||
NetID: networkID,
|
NetID: networkID,
|
||||||
BCID: chainID,
|
BCID: chainID,
|
||||||
Ins: []*TransferableInput{
|
Ins: []*ava.TransferableInput{&ava.TransferableInput{
|
||||||
&TransferableInput{
|
UTXOID: ava.UTXOID{
|
||||||
UTXOID: ava.UTXOID{
|
TxID: firstTx.ID(),
|
||||||
TxID: firstTx.ID(),
|
OutputIndex: 0,
|
||||||
OutputIndex: 0,
|
},
|
||||||
},
|
Asset: ava.Asset{ID: genesisTx.ID()},
|
||||||
Asset: ava.Asset{ID: genesisTx.ID()},
|
In: &secp256k1fx.TransferInput{
|
||||||
In: &secp256k1fx.TransferInput{
|
Amt: 50000,
|
||||||
Amt: 50000,
|
Input: secp256k1fx.Input{
|
||||||
Input: secp256k1fx.Input{
|
SigIndices: []uint32{
|
||||||
SigIndices: []uint32{
|
0,
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
unsignedBytes, err = vm.codec.Marshal(&secondTx.UnsignedTx)
|
unsignedBytes, err = vm.codec.Marshal(&secondTx.UnsignedTx)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package ava
|
||||||
|
|
||||||
|
// TestVerifiable ...
|
||||||
|
type TestVerifiable struct{ Err error }
|
||||||
|
|
||||||
|
// Verify ...
|
||||||
|
func (v *TestVerifiable) Verify() error { return v.Err }
|
||||||
|
|
||||||
|
// TestTransferable ...
|
||||||
|
type TestTransferable struct {
|
||||||
|
TestVerifiable
|
||||||
|
|
||||||
|
Val uint64 `serialize:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Amount ...
|
||||||
|
func (t *TestTransferable) Amount() uint64 { return t.Val }
|
|
@ -1,7 +1,7 @@
|
||||||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
// See the file LICENSE for licensing terms.
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
package avm
|
package ava
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,7 +9,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/utils"
|
"github.com/ava-labs/gecko/utils"
|
||||||
"github.com/ava-labs/gecko/vms/components/ava"
|
|
||||||
"github.com/ava-labs/gecko/vms/components/codec"
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
"github.com/ava-labs/gecko/vms/components/verify"
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
)
|
)
|
||||||
|
@ -22,15 +21,25 @@ var (
|
||||||
errNilTransferableFxInput = errors.New("nil transferable feature extension input is not valid")
|
errNilTransferableFxInput = errors.New("nil transferable feature extension input is not valid")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Transferable is the interface a feature extension must provide to transfer
|
||||||
|
// value between features extensions.
|
||||||
|
type Transferable interface {
|
||||||
|
verify.Verifiable
|
||||||
|
|
||||||
|
// Amount returns how much value this output consumes of the asset in its
|
||||||
|
// transaction.
|
||||||
|
Amount() uint64
|
||||||
|
}
|
||||||
|
|
||||||
// TransferableOutput ...
|
// TransferableOutput ...
|
||||||
type TransferableOutput struct {
|
type TransferableOutput struct {
|
||||||
ava.Asset `serialize:"true"`
|
Asset `serialize:"true"`
|
||||||
|
|
||||||
Out FxTransferable `serialize:"true"`
|
Out Transferable `serialize:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output returns the feature extension output that this Output is using.
|
// Output returns the feature extension output that this Output is using.
|
||||||
func (out *TransferableOutput) Output() FxTransferable { return out.Out }
|
func (out *TransferableOutput) Output() Transferable { return out.Out }
|
||||||
|
|
||||||
// Verify implements the verify.Verifiable interface
|
// Verify implements the verify.Verifiable interface
|
||||||
func (out *TransferableOutput) Verify() error {
|
func (out *TransferableOutput) Verify() error {
|
||||||
|
@ -88,14 +97,14 @@ func IsSortedTransferableOutputs(outs []*TransferableOutput, c codec.Codec) bool
|
||||||
|
|
||||||
// TransferableInput ...
|
// TransferableInput ...
|
||||||
type TransferableInput struct {
|
type TransferableInput struct {
|
||||||
ava.UTXOID `serialize:"true"`
|
UTXOID `serialize:"true"`
|
||||||
ava.Asset `serialize:"true"`
|
Asset `serialize:"true"`
|
||||||
|
|
||||||
In FxTransferable `serialize:"true"`
|
In Transferable `serialize:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input returns the feature extension input that this Input is using.
|
// Input returns the feature extension input that this Input is using.
|
||||||
func (in *TransferableInput) Input() FxTransferable { return in.In }
|
func (in *TransferableInput) Input() Transferable { return in.In }
|
||||||
|
|
||||||
// Verify implements the verify.Verifiable interface
|
// Verify implements the verify.Verifiable interface
|
||||||
func (in *TransferableInput) Verify() error {
|
func (in *TransferableInput) Verify() error {
|
||||||
|
@ -127,7 +136,10 @@ func (ins innerSortTransferableInputs) Less(i, j int) bool {
|
||||||
func (ins innerSortTransferableInputs) Len() int { return len(ins) }
|
func (ins innerSortTransferableInputs) Len() int { return len(ins) }
|
||||||
func (ins innerSortTransferableInputs) Swap(i, j int) { ins[j], ins[i] = ins[i], ins[j] }
|
func (ins innerSortTransferableInputs) Swap(i, j int) { ins[j], ins[i] = ins[i], ins[j] }
|
||||||
|
|
||||||
func sortTransferableInputs(ins []*TransferableInput) { sort.Sort(innerSortTransferableInputs(ins)) }
|
// SortTransferableInputs ...
|
||||||
func isSortedAndUniqueTransferableInputs(ins []*TransferableInput) bool {
|
func SortTransferableInputs(ins []*TransferableInput) { sort.Sort(innerSortTransferableInputs(ins)) }
|
||||||
|
|
||||||
|
// IsSortedAndUniqueTransferableInputs ...
|
||||||
|
func IsSortedAndUniqueTransferableInputs(ins []*TransferableInput) bool {
|
||||||
return utils.IsSortedAndUnique(innerSortTransferableInputs(ins))
|
return utils.IsSortedAndUnique(innerSortTransferableInputs(ins))
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
// See the file LICENSE for licensing terms.
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
package avm
|
package ava
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
"github.com/ava-labs/gecko/utils/formatting"
|
"github.com/ava-labs/gecko/utils/formatting"
|
||||||
"github.com/ava-labs/gecko/vms/components/ava"
|
|
||||||
"github.com/ava-labs/gecko/vms/components/codec"
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
)
|
)
|
||||||
|
@ -22,7 +21,7 @@ func TestTransferableOutputVerifyNil(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransferableOutputVerifyNilFx(t *testing.T) {
|
func TestTransferableOutputVerifyNilFx(t *testing.T) {
|
||||||
to := &TransferableOutput{Asset: ava.Asset{ID: ids.Empty}}
|
to := &TransferableOutput{Asset: Asset{ID: ids.Empty}}
|
||||||
if err := to.Verify(); err == nil {
|
if err := to.Verify(); err == nil {
|
||||||
t.Fatalf("Should have errored due to nil transferable fx output")
|
t.Fatalf("Should have errored due to nil transferable fx output")
|
||||||
}
|
}
|
||||||
|
@ -30,7 +29,7 @@ func TestTransferableOutputVerifyNilFx(t *testing.T) {
|
||||||
|
|
||||||
func TestTransferableOutputVerify(t *testing.T) {
|
func TestTransferableOutputVerify(t *testing.T) {
|
||||||
to := &TransferableOutput{
|
to := &TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
Out: &TestTransferable{Val: 1},
|
Out: &TestTransferable{Val: 1},
|
||||||
}
|
}
|
||||||
if err := to.Verify(); err != nil {
|
if err := to.Verify(); err != nil {
|
||||||
|
@ -47,23 +46,23 @@ func TestTransferableOutputSorting(t *testing.T) {
|
||||||
|
|
||||||
outs := []*TransferableOutput{
|
outs := []*TransferableOutput{
|
||||||
&TransferableOutput{
|
&TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.NewID([32]byte{1})},
|
Asset: Asset{ID: ids.NewID([32]byte{1})},
|
||||||
Out: &TestTransferable{Val: 1},
|
Out: &TestTransferable{Val: 1},
|
||||||
},
|
},
|
||||||
&TransferableOutput{
|
&TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
Out: &TestTransferable{Val: 1},
|
Out: &TestTransferable{Val: 1},
|
||||||
},
|
},
|
||||||
&TransferableOutput{
|
&TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.NewID([32]byte{1})},
|
Asset: Asset{ID: ids.NewID([32]byte{1})},
|
||||||
Out: &TestTransferable{Val: 0},
|
Out: &TestTransferable{Val: 0},
|
||||||
},
|
},
|
||||||
&TransferableOutput{
|
&TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
Out: &TestTransferable{Val: 0},
|
Out: &TestTransferable{Val: 0},
|
||||||
},
|
},
|
||||||
&TransferableOutput{
|
&TransferableOutput{
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
Out: &TestTransferable{Val: 0},
|
Out: &TestTransferable{Val: 0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -115,7 +114,7 @@ func TestTransferableOutputSerialization(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out := &TransferableOutput{
|
out := &TransferableOutput{
|
||||||
Asset: ava.Asset{
|
Asset: Asset{
|
||||||
ID: ids.NewID([32]byte{
|
ID: ids.NewID([32]byte{
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
|
@ -165,8 +164,8 @@ func TestTransferableInputVerifyNil(t *testing.T) {
|
||||||
|
|
||||||
func TestTransferableInputVerifyNilFx(t *testing.T) {
|
func TestTransferableInputVerifyNilFx(t *testing.T) {
|
||||||
ti := &TransferableInput{
|
ti := &TransferableInput{
|
||||||
UTXOID: ava.UTXOID{TxID: ids.Empty},
|
UTXOID: UTXOID{TxID: ids.Empty},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
}
|
}
|
||||||
if err := ti.Verify(); err == nil {
|
if err := ti.Verify(); err == nil {
|
||||||
t.Fatalf("Should have errored due to nil transferable fx input")
|
t.Fatalf("Should have errored due to nil transferable fx input")
|
||||||
|
@ -175,8 +174,8 @@ func TestTransferableInputVerifyNilFx(t *testing.T) {
|
||||||
|
|
||||||
func TestTransferableInputVerify(t *testing.T) {
|
func TestTransferableInputVerify(t *testing.T) {
|
||||||
ti := &TransferableInput{
|
ti := &TransferableInput{
|
||||||
UTXOID: ava.UTXOID{TxID: ids.Empty},
|
UTXOID: UTXOID{TxID: ids.Empty},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
}
|
}
|
||||||
if err := ti.Verify(); err != nil {
|
if err := ti.Verify(); err != nil {
|
||||||
|
@ -193,57 +192,57 @@ func TestTransferableInputSorting(t *testing.T) {
|
||||||
|
|
||||||
ins := []*TransferableInput{
|
ins := []*TransferableInput{
|
||||||
&TransferableInput{
|
&TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.NewID([32]byte{1}),
|
TxID: ids.NewID([32]byte{1}),
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
},
|
},
|
||||||
&TransferableInput{
|
&TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.NewID([32]byte{1}),
|
TxID: ids.NewID([32]byte{1}),
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
},
|
},
|
||||||
&TransferableInput{
|
&TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
},
|
},
|
||||||
&TransferableInput{
|
&TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 0,
|
OutputIndex: 0,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSortedAndUniqueTransferableInputs(ins) {
|
if IsSortedAndUniqueTransferableInputs(ins) {
|
||||||
t.Fatalf("Shouldn't be sorted")
|
t.Fatalf("Shouldn't be sorted")
|
||||||
}
|
}
|
||||||
sortTransferableInputs(ins)
|
SortTransferableInputs(ins)
|
||||||
if !isSortedAndUniqueTransferableInputs(ins) {
|
if !IsSortedAndUniqueTransferableInputs(ins) {
|
||||||
t.Fatalf("Should be sorted")
|
t.Fatalf("Should be sorted")
|
||||||
}
|
}
|
||||||
|
|
||||||
ins = append(ins, &TransferableInput{
|
ins = append(ins, &TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.Empty,
|
TxID: ids.Empty,
|
||||||
OutputIndex: 1,
|
OutputIndex: 1,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{ID: ids.Empty},
|
Asset: Asset{ID: ids.Empty},
|
||||||
In: &TestTransferable{},
|
In: &TestTransferable{},
|
||||||
})
|
})
|
||||||
|
|
||||||
if isSortedAndUniqueTransferableInputs(ins) {
|
if IsSortedAndUniqueTransferableInputs(ins) {
|
||||||
t.Fatalf("Shouldn't be unique")
|
t.Fatalf("Shouldn't be unique")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,7 +271,7 @@ func TestTransferableInputSerialization(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
in := &TransferableInput{
|
in := &TransferableInput{
|
||||||
UTXOID: ava.UTXOID{
|
UTXOID: UTXOID{
|
||||||
TxID: ids.NewID([32]byte{
|
TxID: ids.NewID([32]byte{
|
||||||
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
|
0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81,
|
||||||
0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
|
0x71, 0x61, 0x51, 0x41, 0x31, 0x21, 0x11, 0x01,
|
||||||
|
@ -281,7 +280,7 @@ func TestTransferableInputSerialization(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
OutputIndex: 5,
|
OutputIndex: 5,
|
||||||
},
|
},
|
||||||
Asset: ava.Asset{
|
Asset: Asset{
|
||||||
ID: ids.NewID([32]byte{
|
ID: ids.NewID([32]byte{
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
@ -0,0 +1,150 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package platformvm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/database"
|
||||||
|
"github.com/ava-labs/gecko/database/versiondb"
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
"github.com/ava-labs/gecko/snow/choices"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errConflictingParentTxs = errors.New("block contains a transaction that conflicts with a transaction in a parent block")
|
||||||
|
)
|
||||||
|
|
||||||
|
// AtomicTx is an operation that can be decided without being proposed, but must have special control over database commitment
|
||||||
|
type AtomicTx interface {
|
||||||
|
initialize(vm *VM) error
|
||||||
|
|
||||||
|
// UTXOs this tx consumes
|
||||||
|
InputUTXOs() ids.Set
|
||||||
|
|
||||||
|
// Attempt to verify this transaction with the provided state. The provided
|
||||||
|
// database can be modified arbitrarily.
|
||||||
|
SemanticVerify(database.Database) error
|
||||||
|
|
||||||
|
Accept(database.Batch) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtomicBlock being accepted results in the transaction contained in the
|
||||||
|
// block to be accepted and committed to the chain.
|
||||||
|
type AtomicBlock struct {
|
||||||
|
CommonDecisionBlock `serialize:"true"`
|
||||||
|
|
||||||
|
Tx AtomicTx `serialize:"true"`
|
||||||
|
|
||||||
|
inputs ids.Set
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize this block
|
||||||
|
func (ab *AtomicBlock) initialize(vm *VM, bytes []byte) error {
|
||||||
|
if err := ab.CommonDecisionBlock.initialize(vm, bytes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ab.Tx.initialize(vm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject implements the snowman.Block interface
|
||||||
|
func (ab *AtomicBlock) conflicts(s ids.Set) bool {
|
||||||
|
if ab.Status() == choices.Accepted {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ab.inputs.Overlaps(s) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return ab.parentBlock().conflicts(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify this block performs a valid state transition.
|
||||||
|
//
|
||||||
|
// The parent block must be a proposal
|
||||||
|
//
|
||||||
|
// This function also sets onAcceptDB database if the verification passes.
|
||||||
|
func (ab *AtomicBlock) Verify() error {
|
||||||
|
parentBlock := ab.parentBlock()
|
||||||
|
// AtomicBlock is not a modifier on a proposal block, so its parent must be
|
||||||
|
// a decision.
|
||||||
|
parent, ok := parentBlock.(decision)
|
||||||
|
if !ok {
|
||||||
|
return errInvalidBlockType
|
||||||
|
}
|
||||||
|
|
||||||
|
pdb := parent.onAccept()
|
||||||
|
|
||||||
|
ab.onAcceptDB = versiondb.New(pdb)
|
||||||
|
if err := ab.Tx.SemanticVerify(ab.onAcceptDB); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ab.inputs = ab.Tx.InputUTXOs()
|
||||||
|
|
||||||
|
if parentBlock.conflicts(ab.inputs) {
|
||||||
|
return errConflictingParentTxs
|
||||||
|
}
|
||||||
|
|
||||||
|
ab.vm.currentBlocks[ab.ID().Key()] = ab
|
||||||
|
ab.parentBlock().addChild(ab)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept implements the snowman.Block interface
|
||||||
|
func (ab *AtomicBlock) Accept() {
|
||||||
|
ab.vm.Ctx.Log.Verbo("Accepting block with ID %s", ab.ID())
|
||||||
|
|
||||||
|
ab.CommonBlock.Accept()
|
||||||
|
|
||||||
|
// Update the state of the chain in the database
|
||||||
|
if err := ab.onAcceptDB.Commit(); err != nil {
|
||||||
|
ab.vm.Ctx.Log.Error("unable to commit onAcceptDB")
|
||||||
|
}
|
||||||
|
|
||||||
|
batch, err := ab.vm.DB.CommitBatch()
|
||||||
|
if err != nil {
|
||||||
|
ab.vm.Ctx.Log.Fatal("unable to commit vm's DB")
|
||||||
|
}
|
||||||
|
defer ab.vm.DB.Abort()
|
||||||
|
|
||||||
|
if err := ab.Tx.Accept(batch); err != nil {
|
||||||
|
ab.vm.Ctx.Log.Error("unable to atomically commit block")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range ab.children {
|
||||||
|
child.setBaseDatabase(ab.vm.DB)
|
||||||
|
}
|
||||||
|
if ab.onAcceptFunc != nil {
|
||||||
|
ab.onAcceptFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := ab.parentBlock()
|
||||||
|
// remove this block and its parent from memory
|
||||||
|
parent.free()
|
||||||
|
ab.free()
|
||||||
|
}
|
||||||
|
|
||||||
|
// newAtomicBlock returns a new *AtomicBlock where the block's parent, a
|
||||||
|
// decision block, has ID [parentID].
|
||||||
|
func (vm *VM) newAtomicBlock(parentID ids.ID, tx AtomicTx) (*AtomicBlock, error) {
|
||||||
|
ab := &AtomicBlock{
|
||||||
|
CommonDecisionBlock: CommonDecisionBlock{
|
||||||
|
CommonBlock: CommonBlock{
|
||||||
|
Block: core.NewBlock(parentID),
|
||||||
|
vm: vm,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tx: tx,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We serialize this block as a Block so that it can be deserialized into a
|
||||||
|
// Block
|
||||||
|
blk := Block(ab)
|
||||||
|
bytes, err := Codec.Marshal(&blk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ab.Block.Initialize(bytes, vm.SnowmanVM)
|
||||||
|
return ab, nil
|
||||||
|
}
|
|
@ -71,9 +71,6 @@ func (tx *CreateChainTx) Key() crypto.PublicKey { return tx.key }
|
||||||
// Bytes returns the byte representation of a CreateChainTx
|
// Bytes returns the byte representation of a CreateChainTx
|
||||||
func (tx *CreateChainTx) Bytes() []byte { return tx.bytes }
|
func (tx *CreateChainTx) Bytes() []byte { return tx.bytes }
|
||||||
|
|
||||||
// InputUTXOs returns an empty set
|
|
||||||
func (tx *CreateChainTx) InputUTXOs() ids.Set { return ids.Set{} }
|
|
||||||
|
|
||||||
// SyntacticVerify this transaction is well-formed
|
// SyntacticVerify this transaction is well-formed
|
||||||
// Also populates [tx.Key] with the public key that signed this transaction
|
// Also populates [tx.Key] with the public key that signed this transaction
|
||||||
func (tx *CreateChainTx) SyntacticVerify() error {
|
func (tx *CreateChainTx) SyntacticVerify() error {
|
||||||
|
|
|
@ -144,9 +144,6 @@ func (tx *CreateSubnetTx) Bytes() []byte {
|
||||||
return tx.bytes
|
return tx.bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputUTXOs returns an empty set
|
|
||||||
func (tx *CreateSubnetTx) InputUTXOs() ids.Set { return ids.Set{} }
|
|
||||||
|
|
||||||
// initialize sets [tx.vm] to [vm]
|
// initialize sets [tx.vm] to [vm]
|
||||||
func (tx *CreateSubnetTx) initialize(vm *VM) error {
|
func (tx *CreateSubnetTx) initialize(vm *VM) error {
|
||||||
tx.vm = vm
|
tx.vm = vm
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package platformvm
|
||||||
|
|
||||||
|
// import (
|
||||||
|
// "fmt"
|
||||||
|
|
||||||
|
// "github.com/ava-labs/gecko/chains"
|
||||||
|
// "github.com/ava-labs/gecko/database"
|
||||||
|
// "github.com/ava-labs/gecko/ids"
|
||||||
|
// "github.com/ava-labs/gecko/utils/crypto"
|
||||||
|
// "github.com/ava-labs/gecko/utils/hashing"
|
||||||
|
// "github.com/ava-labs/gecko/vms/components/ava"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// // UnsignedExportTx is an unsigned ExportTx
|
||||||
|
// type UnsignedExportTx struct {
|
||||||
|
// // ID of the network this blockchain exists on
|
||||||
|
// NetworkID uint32 `serialize:"true"`
|
||||||
|
|
||||||
|
// // Next unused nonce of account paying the transaction fee for this transaction.
|
||||||
|
// // Currently unused, as there are no tx fees.
|
||||||
|
// Nonce uint64 `serialize:"true"`
|
||||||
|
|
||||||
|
// Outs []*ava.TransferableOutput `serialize:"true"` // The outputs of this transaction
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ExportTx exports funds to the AVM
|
||||||
|
// type ExportTx struct {
|
||||||
|
// UnsignedExportTx `serialize:"true"`
|
||||||
|
|
||||||
|
// Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||||
|
|
||||||
|
// vm *VM
|
||||||
|
// id ids.ID
|
||||||
|
// key crypto.PublicKey // public key of transaction signer
|
||||||
|
// bytes []byte
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (tx *ExportTx) initialize(vm *VM) error {
|
||||||
|
// tx.vm = vm
|
||||||
|
// txBytes, err := Codec.Marshal(tx) // byte repr. of the signed tx
|
||||||
|
// tx.bytes = txBytes
|
||||||
|
// tx.id = ids.NewID(hashing.ComputeHash256Array(txBytes))
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ID of this transaction
|
||||||
|
// func (tx *ExportTx) ID() ids.ID { return tx.id }
|
||||||
|
|
||||||
|
// // Key returns the public key of the signer of this transaction
|
||||||
|
// // Precondition: tx.Verify() has been called and returned nil
|
||||||
|
// func (tx *ExportTx) Key() crypto.PublicKey { return tx.key }
|
||||||
|
|
||||||
|
// // Bytes returns the byte representation of a CreateChainTx
|
||||||
|
// func (tx *ExportTx) Bytes() []byte { return tx.bytes }
|
||||||
|
|
||||||
|
// // InputUTXOs returns an empty set
|
||||||
|
// func (tx *ExportTx) InputUTXOs() ids.Set { return ids.Set{} }
|
||||||
|
|
||||||
|
// // SyntacticVerify this transaction is well-formed
|
||||||
|
// // Also populates [tx.Key] with the public key that signed this transaction
|
||||||
|
// func (tx *ExportTx) SyntacticVerify() error {
|
||||||
|
// switch {
|
||||||
|
// case tx == nil:
|
||||||
|
// return errNilTx
|
||||||
|
// case tx.key != nil:
|
||||||
|
// return nil // Only verify the transaction once
|
||||||
|
// case tx.NetworkID != tx.vm.Ctx.NetworkID: // verify the transaction is on this network
|
||||||
|
// return errWrongNetworkID
|
||||||
|
// case tx.id.IsZero():
|
||||||
|
// return errInvalidID
|
||||||
|
// }
|
||||||
|
|
||||||
|
// unsignedIntf := interface{}(&tx.UnsignedImportTx)
|
||||||
|
// unsignedBytes, err := Codec.Marshal(&unsignedIntf) // byte repr of unsigned tx
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// key, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.Sig[:])
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// tx.key = key
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // SemanticVerify this transaction is valid.
|
||||||
|
// func (tx *ExportTx) SemanticVerify(db database.Database) (func(), error) {
|
||||||
|
// if err := tx.SyntacticVerify(); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// currentChains, err := tx.vm.getChains(db) // chains that currently exist
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, errDBChains
|
||||||
|
// }
|
||||||
|
// for _, chain := range currentChains {
|
||||||
|
// if chain.ID().Equals(tx.ID()) {
|
||||||
|
// return nil, fmt.Errorf("chain with ID %s already exists", chain.ID())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// currentChains = append(currentChains, tx) // add this new chain
|
||||||
|
// if err := tx.vm.putChains(db, currentChains); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Deduct tx fee from payer's account
|
||||||
|
// account, err := tx.vm.getAccount(db, tx.Key().Address())
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// account, err = account.Remove(0, tx.Nonce)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// if err := tx.vm.putAccount(db, account); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // If this proposal is committed, create the new blockchain using the chain manager
|
||||||
|
// onAccept := func() {
|
||||||
|
// chainParams := chains.ChainParameters{
|
||||||
|
// ID: tx.ID(),
|
||||||
|
// GenesisData: tx.GenesisData,
|
||||||
|
// VMAlias: tx.VMID.String(),
|
||||||
|
// }
|
||||||
|
// for _, fxID := range tx.FxIDs {
|
||||||
|
// chainParams.FxAliases = append(chainParams.FxAliases, fxID.String())
|
||||||
|
// }
|
||||||
|
// // TODO: Not sure how else to make this not nil pointer error during tests
|
||||||
|
// if tx.vm.ChainManager != nil {
|
||||||
|
// tx.vm.ChainManager.CreateChain(chainParams)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return onAccept, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (vm *VM) newExportTx(nonce uint64, genesisData []byte, vmID ids.ID, fxIDs []ids.ID, chainName string, networkID uint32, key *crypto.PrivateKeySECP256K1R) (*ExportTx, error) {
|
||||||
|
// tx := &CreateChainTx{
|
||||||
|
// UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||||
|
// NetworkID: networkID,
|
||||||
|
// Nonce: nonce,
|
||||||
|
// GenesisData: genesisData,
|
||||||
|
// VMID: vmID,
|
||||||
|
// FxIDs: fxIDs,
|
||||||
|
// ChainName: chainName,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
|
// unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||||
|
// unsignedBytes, err := Codec.Marshal(&unsignedIntf) // Byte repr. of unsigned transaction
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// sig, err := key.Sign(unsignedBytes)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// copy(tx.Sig[:], sig)
|
||||||
|
|
||||||
|
// return tx, tx.initialize(vm)
|
||||||
|
// }
|
|
@ -0,0 +1,252 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package platformvm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/chains/atomic"
|
||||||
|
"github.com/ava-labs/gecko/database"
|
||||||
|
"github.com/ava-labs/gecko/database/versiondb"
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
"github.com/ava-labs/gecko/snow/choices"
|
||||||
|
"github.com/ava-labs/gecko/utils/crypto"
|
||||||
|
"github.com/ava-labs/gecko/utils/hashing"
|
||||||
|
"github.com/ava-labs/gecko/utils/math"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/ava"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo")
|
||||||
|
errWrongNumberOfCredentials = errors.New("should have the same number of credentials as inputs")
|
||||||
|
errNoImportInputs = errors.New("no import inputs")
|
||||||
|
errInputsNotSortedUnique = errors.New("inputs not sorted and unique")
|
||||||
|
errPublicKeySignatureMismatch = errors.New("signature doesn't match public key")
|
||||||
|
errUnknownAsset = errors.New("unknown asset ID")
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnsignedImportTx is an unsigned ImportTx
|
||||||
|
type UnsignedImportTx struct {
|
||||||
|
// ID of the network this blockchain exists on
|
||||||
|
NetworkID uint32 `serialize:"true"`
|
||||||
|
|
||||||
|
// Next unused nonce of account paying the transaction fee for this transaction.
|
||||||
|
// Currently unused, as there are no tx fees.
|
||||||
|
Nonce uint64 `serialize:"true"`
|
||||||
|
|
||||||
|
// Account that this transaction is being sent by. This is needed to ensure the Credentials are replay safe.
|
||||||
|
Account [crypto.SECP256K1RPKLen]byte `serialize:"true"`
|
||||||
|
|
||||||
|
Ins []*ava.TransferableInput `serialize:"true"` // The inputs to this transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportTx imports funds from the AVM
|
||||||
|
type ImportTx struct {
|
||||||
|
UnsignedImportTx `serialize:"true"`
|
||||||
|
|
||||||
|
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||||
|
Creds []verify.Verifiable `serialize:"true"` // The credentials of this transaction
|
||||||
|
|
||||||
|
vm *VM
|
||||||
|
id ids.ID
|
||||||
|
key crypto.PublicKey // public key of transaction signer
|
||||||
|
bytes []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *ImportTx) initialize(vm *VM) error {
|
||||||
|
tx.vm = vm
|
||||||
|
txBytes, err := Codec.Marshal(tx) // byte repr. of the signed tx
|
||||||
|
tx.bytes = txBytes
|
||||||
|
tx.id = ids.NewID(hashing.ComputeHash256Array(txBytes))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID of this transaction
|
||||||
|
func (tx *ImportTx) ID() ids.ID { return tx.id }
|
||||||
|
|
||||||
|
// Key returns the public key of the signer of this transaction
|
||||||
|
// Precondition: tx.Verify() has been called and returned nil
|
||||||
|
func (tx *ImportTx) Key() crypto.PublicKey { return tx.key }
|
||||||
|
|
||||||
|
// Bytes returns the byte representation of a CreateChainTx
|
||||||
|
func (tx *ImportTx) Bytes() []byte { return tx.bytes }
|
||||||
|
|
||||||
|
// InputUTXOs returns an empty set
|
||||||
|
func (tx *ImportTx) InputUTXOs() ids.Set {
|
||||||
|
set := ids.Set{}
|
||||||
|
for _, in := range tx.Ins {
|
||||||
|
set.Add(in.InputID())
|
||||||
|
}
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyntacticVerify this transaction is well-formed
|
||||||
|
// Also populates [tx.Key] with the public key that signed this transaction
|
||||||
|
func (tx *ImportTx) SyntacticVerify() error {
|
||||||
|
switch {
|
||||||
|
case tx == nil:
|
||||||
|
return errNilTx
|
||||||
|
case tx.key != nil:
|
||||||
|
return nil // Only verify the transaction once
|
||||||
|
case tx.NetworkID != tx.vm.Ctx.NetworkID: // verify the transaction is on this network
|
||||||
|
return errWrongNetworkID
|
||||||
|
case tx.id.IsZero():
|
||||||
|
return errInvalidID
|
||||||
|
case len(tx.Ins) == 0:
|
||||||
|
return errNoImportInputs
|
||||||
|
case len(tx.Ins) != len(tx.Creds):
|
||||||
|
return errWrongNumberOfCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, in := range tx.Ins {
|
||||||
|
if err := in.Verify(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !in.AssetID().Equals(tx.vm.AVA) {
|
||||||
|
return errUnknownAsset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ava.IsSortedAndUniqueTransferableInputs(tx.Ins) {
|
||||||
|
return errInputsNotSortedUnique
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cred := range tx.Creds {
|
||||||
|
if err := cred.Verify(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsignedIntf := interface{}(&tx.UnsignedImportTx)
|
||||||
|
unsignedBytes, err := Codec.Marshal(&unsignedIntf) // byte repr of unsigned tx
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPublicKey, err := tx.vm.factory.ToPublicKey(tx.Account[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.Sig[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !expectedPublicKey.Address().Equals(key.Address()) {
|
||||||
|
return errPublicKeySignatureMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.key = key
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemanticVerify this transaction is valid.
|
||||||
|
func (tx *ImportTx) SemanticVerify(db database.Database) error {
|
||||||
|
if err := tx.SyntacticVerify(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bID := ids.Empty // TODO: Needs to be set to the platform chain
|
||||||
|
smDB := tx.vm.Ctx.SharedMemory.GetDatabase(bID)
|
||||||
|
defer tx.vm.Ctx.SharedMemory.ReleaseDatabase(bID)
|
||||||
|
|
||||||
|
state := ava.NewPrefixedState(smDB, Codec)
|
||||||
|
|
||||||
|
amount := uint64(0)
|
||||||
|
for i, in := range tx.Ins {
|
||||||
|
newAmount, err := math.Add64(in.In.Amount(), amount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
amount = newAmount
|
||||||
|
|
||||||
|
cred := tx.Creds[i]
|
||||||
|
|
||||||
|
utxoID := in.UTXOID.InputID()
|
||||||
|
utxo, err := state.AVMUTXO(utxoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utxoAssetID := utxo.AssetID()
|
||||||
|
inAssetID := in.AssetID()
|
||||||
|
if !utxoAssetID.Equals(inAssetID) {
|
||||||
|
return errAssetIDMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.vm.fx.VerifyTransfer(uTx, utxo.Out, in.In, cred); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct tx fee from payer's account
|
||||||
|
account, err := tx.vm.getAccount(db, tx.Key().Address())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
account, err = account.Remove(0, tx.Nonce)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
account, err = account.Add(amount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.vm.putAccount(db, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept this transaction.
|
||||||
|
func (tx *ImportTx) Accept(batch database.Batch) error {
|
||||||
|
bID := ids.Empty // TODO: Needs to be set to the platform chain
|
||||||
|
smDB := tx.vm.Ctx.SharedMemory.GetDatabase(bID)
|
||||||
|
defer tx.vm.Ctx.SharedMemory.ReleaseDatabase(bID)
|
||||||
|
|
||||||
|
vsmDB := versiondb.New(smDB)
|
||||||
|
|
||||||
|
state := ava.NewPrefixedState(vsmDB, Codec)
|
||||||
|
for _, in := range tx.Ins {
|
||||||
|
utxoID := in.UTXOID.InputID()
|
||||||
|
if _, err := state.AVMUTXO(utxoID); err == nil {
|
||||||
|
if err := state.SetAVMUTXO(utxoID, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := state.SetAVMStatus(utxoID, choices.Accepted); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedBatch, err := vsmDB.CommitBatch()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return atomic.WriteAll(batch, sharedBatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) newImportTx(nonce uint64, genesisData []byte, vmID ids.ID, fxIDs []ids.ID, chainName string, networkID uint32, key *crypto.PrivateKeySECP256K1R) (*ImportTx, error) {
|
||||||
|
tx := &CreateChainTx{
|
||||||
|
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||||
|
NetworkID: networkID,
|
||||||
|
Nonce: nonce,
|
||||||
|
GenesisData: genesisData,
|
||||||
|
VMID: vmID,
|
||||||
|
FxIDs: fxIDs,
|
||||||
|
ChainName: chainName,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||||
|
unsignedBytes, err := Codec.Marshal(&unsignedIntf) // Byte repr. of unsigned transaction
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := key.Sign(unsignedBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
copy(tx.Sig[:], sig)
|
||||||
|
|
||||||
|
return tx, tx.initialize(vm)
|
||||||
|
}
|
|
@ -4,26 +4,16 @@
|
||||||
package platformvm
|
package platformvm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"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/ids"
|
||||||
"github.com/ava-labs/gecko/snow/choices"
|
|
||||||
"github.com/ava-labs/gecko/vms/components/core"
|
"github.com/ava-labs/gecko/vms/components/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errConflictingParentTxs = errors.New("block contains a transaction that conflicts with a transaction in a parent block")
|
|
||||||
errConflictingTxs = errors.New("block contains conflicting transactions")
|
|
||||||
)
|
|
||||||
|
|
||||||
// DecisionTx is an operation that can be decided without being proposed
|
// DecisionTx is an operation that can be decided without being proposed
|
||||||
type DecisionTx interface {
|
type DecisionTx interface {
|
||||||
initialize(vm *VM) error
|
initialize(vm *VM) error
|
||||||
|
|
||||||
InputUTXOs() ids.Set
|
|
||||||
|
|
||||||
// Attempt to verify this transaction with the provided state. The provided
|
// Attempt to verify this transaction with the provided state. The provided
|
||||||
// database can be modified arbitrarily. If a nil error is returned, it is
|
// database can be modified arbitrarily. If a nil error is returned, it is
|
||||||
// assumped onAccept is non-nil.
|
// assumped onAccept is non-nil.
|
||||||
|
@ -36,8 +26,6 @@ type StandardBlock struct {
|
||||||
CommonDecisionBlock `serialize:"true"`
|
CommonDecisionBlock `serialize:"true"`
|
||||||
|
|
||||||
Txs []DecisionTx `serialize:"true"`
|
Txs []DecisionTx `serialize:"true"`
|
||||||
|
|
||||||
inputs ids.Set
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize this block
|
// initialize this block
|
||||||
|
@ -53,17 +41,6 @@ func (sb *StandardBlock) initialize(vm *VM, bytes []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject implements the snowman.Block interface
|
|
||||||
func (sb *StandardBlock) conflicts(s ids.Set) bool {
|
|
||||||
if sb.Status() == choices.Accepted {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if sb.inputs.Overlaps(s) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return sb.parentBlock().conflicts(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify this block performs a valid state transition.
|
// Verify this block performs a valid state transition.
|
||||||
//
|
//
|
||||||
// The parent block must be a proposal
|
// The parent block must be a proposal
|
||||||
|
@ -87,20 +64,11 @@ func (sb *StandardBlock) Verify() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inputs := tx.InputUTXOs()
|
|
||||||
if inputs.Overlaps(sb.inputs) {
|
|
||||||
return errConflictingTxs
|
|
||||||
}
|
|
||||||
sb.inputs.Union(inputs)
|
|
||||||
if onAccept != nil {
|
if onAccept != nil {
|
||||||
funcs = append(funcs, onAccept)
|
funcs = append(funcs, onAccept)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentBlock.conflicts(sb.inputs) {
|
|
||||||
return errConflictingParentTxs
|
|
||||||
}
|
|
||||||
|
|
||||||
if numFuncs := len(funcs); numFuncs == 1 {
|
if numFuncs := len(funcs); numFuncs == 1 {
|
||||||
sb.onAcceptFunc = funcs[0]
|
sb.onAcceptFunc = funcs[0]
|
||||||
} else if numFuncs > 1 {
|
} else if numFuncs > 1 {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ava-labs/gecko/utils/wrappers"
|
"github.com/ava-labs/gecko/utils/wrappers"
|
||||||
"github.com/ava-labs/gecko/vms/components/codec"
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
"github.com/ava-labs/gecko/vms/components/core"
|
"github.com/ava-labs/gecko/vms/components/core"
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -108,6 +109,13 @@ func init() {
|
||||||
Codec.RegisterType(&Abort{}),
|
Codec.RegisterType(&Abort{}),
|
||||||
Codec.RegisterType(&Commit{}),
|
Codec.RegisterType(&Commit{}),
|
||||||
Codec.RegisterType(&StandardBlock{}),
|
Codec.RegisterType(&StandardBlock{}),
|
||||||
|
Codec.RegisterType(&AtomicBlock{}),
|
||||||
|
|
||||||
|
Codec.RegisterType(&secp256k1fx.MintOutput{}),
|
||||||
|
Codec.RegisterType(&secp256k1fx.TransferOutput{}),
|
||||||
|
Codec.RegisterType(&secp256k1fx.MintInput{}),
|
||||||
|
Codec.RegisterType(&secp256k1fx.TransferInput{}),
|
||||||
|
Codec.RegisterType(&secp256k1fx.Credential{}),
|
||||||
|
|
||||||
Codec.RegisterType(&UnsignedAddDefaultSubnetValidatorTx{}),
|
Codec.RegisterType(&UnsignedAddDefaultSubnetValidatorTx{}),
|
||||||
Codec.RegisterType(&addDefaultSubnetValidatorTx{}),
|
Codec.RegisterType(&addDefaultSubnetValidatorTx{}),
|
||||||
|
@ -124,6 +132,12 @@ func init() {
|
||||||
Codec.RegisterType(&UnsignedCreateSubnetTx{}),
|
Codec.RegisterType(&UnsignedCreateSubnetTx{}),
|
||||||
Codec.RegisterType(&CreateSubnetTx{}),
|
Codec.RegisterType(&CreateSubnetTx{}),
|
||||||
|
|
||||||
|
Codec.RegisterType(&UnsignedImportTx{}),
|
||||||
|
Codec.RegisterType(&ImportTx{}),
|
||||||
|
|
||||||
|
// Codec.RegisterType(&UnsignedExportTx{}),
|
||||||
|
// Codec.RegisterType(&ExportTx{}),
|
||||||
|
|
||||||
Codec.RegisterType(&advanceTimeTx{}),
|
Codec.RegisterType(&advanceTimeTx{}),
|
||||||
Codec.RegisterType(&rewardValidatorTx{}),
|
Codec.RegisterType(&rewardValidatorTx{}),
|
||||||
)
|
)
|
||||||
|
@ -141,6 +155,11 @@ type VM struct {
|
||||||
// The node's chain manager
|
// The node's chain manager
|
||||||
ChainManager chains.Manager
|
ChainManager chains.Manager
|
||||||
|
|
||||||
|
// AVA asset ID
|
||||||
|
AVA ids.ID
|
||||||
|
|
||||||
|
fx secp256k1fx.Fx
|
||||||
|
|
||||||
// Used to create and use keys.
|
// Used to create and use keys.
|
||||||
factory crypto.FactorySECP256K1R
|
factory crypto.FactorySECP256K1R
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ func (w *Wallet) ImportKey(sk *crypto.PrivateKeySECP256K1R) { w.keychain.Add(sk)
|
||||||
// AddUTXO adds a new UTXO to this wallet if this wallet may spend it
|
// AddUTXO adds a new UTXO to this wallet if this wallet may spend it
|
||||||
// The UTXO's output must be an OutputPayment
|
// The UTXO's output must be an OutputPayment
|
||||||
func (w *Wallet) AddUTXO(utxo *ava.UTXO) {
|
func (w *Wallet) AddUTXO(utxo *ava.UTXO) {
|
||||||
out, ok := utxo.Out.(avm.FxTransferable)
|
out, ok := utxo.Out.(ava.Transferable)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ func (w *Wallet) RemoveUTXO(utxoID ids.ID) {
|
||||||
|
|
||||||
assetID := utxo.AssetID()
|
assetID := utxo.AssetID()
|
||||||
assetKey := assetID.Key()
|
assetKey := assetID.Key()
|
||||||
newBalance := w.balance[assetKey] - utxo.Out.(avm.FxTransferable).Amount()
|
newBalance := w.balance[assetKey] - utxo.Out.(ava.Transferable).Amount()
|
||||||
if newBalance == 0 {
|
if newBalance == 0 {
|
||||||
delete(w.balance, assetKey)
|
delete(w.balance, assetKey)
|
||||||
} else {
|
} else {
|
||||||
|
@ -138,7 +138,7 @@ func (w *Wallet) CreateTx(assetID ids.ID, amount uint64, destAddr ids.ShortID) (
|
||||||
amountSpent := uint64(0)
|
amountSpent := uint64(0)
|
||||||
time := w.clock.Unix()
|
time := w.clock.Unix()
|
||||||
|
|
||||||
ins := []*avm.TransferableInput{}
|
ins := []*ava.TransferableInput{}
|
||||||
keys := [][]*crypto.PrivateKeySECP256K1R{}
|
keys := [][]*crypto.PrivateKeySECP256K1R{}
|
||||||
for _, utxo := range w.utxoSet.UTXOs {
|
for _, utxo := range w.utxoSet.UTXOs {
|
||||||
if !utxo.AssetID().Equals(assetID) {
|
if !utxo.AssetID().Equals(assetID) {
|
||||||
|
@ -148,7 +148,7 @@ func (w *Wallet) CreateTx(assetID ids.ID, amount uint64, destAddr ids.ShortID) (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
input, ok := inputIntf.(avm.FxTransferable)
|
input, ok := inputIntf.(ava.Transferable)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ func (w *Wallet) CreateTx(assetID ids.ID, amount uint64, destAddr ids.ShortID) (
|
||||||
}
|
}
|
||||||
amountSpent = spent
|
amountSpent = spent
|
||||||
|
|
||||||
in := &avm.TransferableInput{
|
in := &ava.TransferableInput{
|
||||||
UTXOID: utxo.UTXOID,
|
UTXOID: utxo.UTXOID,
|
||||||
Asset: ava.Asset{ID: assetID},
|
Asset: ava.Asset{ID: assetID},
|
||||||
In: input,
|
In: input,
|
||||||
|
@ -178,41 +178,37 @@ func (w *Wallet) CreateTx(assetID ids.ID, amount uint64, destAddr ids.ShortID) (
|
||||||
|
|
||||||
avm.SortTransferableInputsWithSigners(ins, keys)
|
avm.SortTransferableInputsWithSigners(ins, keys)
|
||||||
|
|
||||||
outs := []*avm.TransferableOutput{
|
outs := []*ava.TransferableOutput{&ava.TransferableOutput{
|
||||||
&avm.TransferableOutput{
|
Asset: ava.Asset{ID: assetID},
|
||||||
Asset: ava.Asset{ID: assetID},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: amount,
|
||||||
Amt: amount,
|
Locktime: 0,
|
||||||
Locktime: 0,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{destAddr},
|
||||||
Addrs: []ids.ShortID{destAddr},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}}
|
||||||
|
|
||||||
if amountSpent > amount {
|
if amountSpent > amount {
|
||||||
changeAddr, err := w.GetAddress()
|
changeAddr, err := w.GetAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outs = append(outs,
|
outs = append(outs, &ava.TransferableOutput{
|
||||||
&avm.TransferableOutput{
|
Asset: ava.Asset{ID: assetID},
|
||||||
Asset: ava.Asset{ID: assetID},
|
Out: &secp256k1fx.TransferOutput{
|
||||||
Out: &secp256k1fx.TransferOutput{
|
Amt: amountSpent - amount,
|
||||||
Amt: amountSpent - amount,
|
Locktime: 0,
|
||||||
Locktime: 0,
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
OutputOwners: secp256k1fx.OutputOwners{
|
Threshold: 1,
|
||||||
Threshold: 1,
|
Addrs: []ids.ShortID{changeAddr},
|
||||||
Addrs: []ids.ShortID{changeAddr},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
avm.SortTransferableOutputs(outs, w.codec)
|
ava.SortTransferableOutputs(outs, w.codec)
|
||||||
|
|
||||||
tx := &avm.Tx{
|
tx := &avm.Tx{
|
||||||
UnsignedTx: &avm.BaseTx{
|
UnsignedTx: &avm.BaseTx{
|
||||||
|
|
Loading…
Reference in New Issue