1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package evm
import (
"testing"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
)
func TestExportTxVerifyNil(t *testing.T) {
var exportTx UnsignedExportTx
if err := exportTx.Verify(testXChainID, NewContext(), testTxFee, testAvaxAssetID); err == nil {
t.Fatal("Verify should have failed due to nil transaction")
}
}
func TestExportTxVerify(t *testing.T) {
var exportAmount uint64 = 10000000
exportTx := &UnsignedExportTx{
NetworkID: testNetworkID,
BlockchainID: testCChainID,
DestinationChain: testXChainID,
Ins: []EVMInput{
{
Address: testEthAddrs[0],
Amount: exportAmount,
AssetID: testAvaxAssetID,
Nonce: 0,
},
{
Address: testEthAddrs[2],
Amount: exportAmount,
AssetID: testAvaxAssetID,
Nonce: 0,
},
},
ExportedOutputs: []*avax.TransferableOutput{
{
Asset: avax.Asset{ID: testAvaxAssetID},
Out: &secp256k1fx.TransferOutput{
Amt: exportAmount - testTxFee,
OutputOwners: secp256k1fx.OutputOwners{
Locktime: 0,
Threshold: 1,
Addrs: []ids.ShortID{testShortIDAddrs[0]},
},
},
},
{
Asset: avax.Asset{ID: testAvaxAssetID},
Out: &secp256k1fx.TransferOutput{
Amt: exportAmount, // only subtract fee from one output
OutputOwners: secp256k1fx.OutputOwners{
Locktime: 0,
Threshold: 1,
Addrs: []ids.ShortID{testShortIDAddrs[1]},
},
},
},
},
}
// Sort the inputs and outputs to ensure the transaction is canonical
avax.SortTransferableOutputs(exportTx.ExportedOutputs, Codec)
// Pass in a list of signers here with the appropriate length
// to avoid causing a nil-pointer error in the helper method
emptySigners := make([][]*crypto.PrivateKeySECP256K1R, 2)
SortEVMInputsAndSigners(exportTx.Ins, emptySigners)
ctx := NewContext()
// Test Valid Export Tx
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err != nil {
t.Fatalf("Failed to verify valid ExportTx: %w", err)
}
exportTx.syntacticallyVerified = false
exportTx.NetworkID = testNetworkID + 1
// Test Incorrect Network ID Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to incorrect network ID")
}
exportTx.syntacticallyVerified = false
exportTx.NetworkID = testNetworkID
exportTx.BlockchainID = nonExistentID
// Test Incorrect Blockchain ID Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to incorrect blockchain ID")
}
exportTx.syntacticallyVerified = false
exportTx.BlockchainID = testCChainID
exportTx.DestinationChain = nonExistentID
// Test Incorrect Destination Chain ID Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to incorrect destination chain")
}
exportTx.syntacticallyVerified = false
exportTx.DestinationChain = testXChainID
exportedOuts := exportTx.ExportedOutputs
exportTx.ExportedOutputs = nil
// Test No Exported Outputs Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to no exported outputs")
}
exportTx.syntacticallyVerified = false
exportTx.ExportedOutputs = []*avax.TransferableOutput{exportedOuts[1], exportedOuts[0]}
// Test Unsorted outputs Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to no exported outputs")
}
exportTx.syntacticallyVerified = false
exportTx.ExportedOutputs = exportedOuts
inputs := exportTx.Ins
exportTx.Ins = nil
// Test No Exported Outputs Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to no inputs")
}
exportTx.syntacticallyVerified = false
exportTx.Ins = []EVMInput{inputs[1], inputs[0]}
// Test unsorted EVM Inputs Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to unsorted inputs")
}
exportTx.syntacticallyVerified = false
exportTx.Ins = []EVMInput{inputs[0], inputs[0]}
// Test non-unique EVM Inputs Errors
if err := exportTx.Verify(testXChainID, ctx, testTxFee, testAvaxAssetID); err == nil {
t.Fatal("ExportTx should have failed verification due to non-unique inputs")
}
}
|