structs_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. package vaa
  2. import (
  3. "crypto/ecdsa"
  4. "crypto/elliptic"
  5. "crypto/rand"
  6. "encoding/hex"
  7. "math/big"
  8. "reflect"
  9. "testing"
  10. "time"
  11. "github.com/ethereum/go-ethereum/common"
  12. "github.com/ethereum/go-ethereum/crypto"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. func TestChainIDFromString(t *testing.T) {
  17. type test struct {
  18. input string
  19. output ChainID
  20. }
  21. // Positive Test Cases
  22. p_tests := []test{
  23. {input: "solana", output: ChainIDSolana},
  24. {input: "ethereum", output: ChainIDEthereum},
  25. {input: "terra", output: ChainIDTerra},
  26. {input: "bsc", output: ChainIDBSC},
  27. {input: "polygon", output: ChainIDPolygon},
  28. {input: "avalanche", output: ChainIDAvalanche},
  29. {input: "oasis", output: ChainIDOasis},
  30. {input: "algorand", output: ChainIDAlgorand},
  31. {input: "aurora", output: ChainIDAurora},
  32. {input: "fantom", output: ChainIDFantom},
  33. {input: "karura", output: ChainIDKarura},
  34. {input: "acala", output: ChainIDAcala},
  35. {input: "klaytn", output: ChainIDKlaytn},
  36. {input: "celo", output: ChainIDCelo},
  37. {input: "moonbeam", output: ChainIDMoonbeam},
  38. {input: "neon", output: ChainIDNeon},
  39. {input: "terra2", output: ChainIDTerra2},
  40. {input: "injective", output: ChainIDInjective},
  41. {input: "ethereum-ropsten", output: ChainIDEthereumRopsten},
  42. {input: "Solana", output: ChainIDSolana},
  43. {input: "Ethereum", output: ChainIDEthereum},
  44. {input: "Terra", output: ChainIDTerra},
  45. {input: "Bsc", output: ChainIDBSC},
  46. {input: "Polygon", output: ChainIDPolygon},
  47. {input: "Avalanche", output: ChainIDAvalanche},
  48. {input: "Oasis", output: ChainIDOasis},
  49. {input: "Algorand", output: ChainIDAlgorand},
  50. {input: "Aurora", output: ChainIDAurora},
  51. {input: "Fantom", output: ChainIDFantom},
  52. {input: "Karura", output: ChainIDKarura},
  53. {input: "Acala", output: ChainIDAcala},
  54. {input: "Klaytn", output: ChainIDKlaytn},
  55. {input: "Celo", output: ChainIDCelo},
  56. {input: "Moonbeam", output: ChainIDMoonbeam},
  57. {input: "Neon", output: ChainIDNeon},
  58. {input: "Terra2", output: ChainIDTerra2},
  59. {input: "Injective", output: ChainIDInjective},
  60. {input: "Ethereum-ropsten", output: ChainIDEthereumRopsten},
  61. }
  62. // Negative Test Cases
  63. n_tests := []test{
  64. {input: "Unknown", output: ChainIDUnset},
  65. }
  66. for _, tc := range p_tests {
  67. t.Run(tc.input, func(t *testing.T) {
  68. chainId, err := ChainIDFromString(tc.input)
  69. assert.Equal(t, tc.output, chainId)
  70. assert.NoError(t, err)
  71. })
  72. }
  73. for _, tc := range n_tests {
  74. t.Run(tc.input, func(t *testing.T) {
  75. chainId, err := ChainIDFromString(tc.input)
  76. assert.Equal(t, tc.output, chainId)
  77. assert.NotNil(t, err)
  78. })
  79. }
  80. }
  81. func TestAddress_MarshalJSON(t *testing.T) {
  82. addr := Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
  83. expected := "223030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303422"
  84. marshalJsonAddress, err := addr.MarshalJSON()
  85. assert.Equal(t, hex.EncodeToString(marshalJsonAddress), expected)
  86. assert.NoError(t, err)
  87. }
  88. func TestAddress_String(t *testing.T) {
  89. addr := Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
  90. expected := "0000000000000000000000000000000000000000000000000000000000000004"
  91. assert.Equal(t, addr.String(), expected)
  92. }
  93. func TestAddress_Bytes(t *testing.T) {
  94. addr := Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
  95. expected := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}
  96. assert.Equal(t, addr.Bytes(), expected)
  97. }
  98. func TestSignatureData_MarshalJSON(t *testing.T) {
  99. sigData := SignatureData{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0}
  100. marshalJsonSigData, err := sigData.MarshalJSON()
  101. require.Nil(t, err)
  102. expected := "223030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303034303022"
  103. assert.Equal(t, hex.EncodeToString(marshalJsonSigData), expected)
  104. }
  105. func TestSignature_DataString(t *testing.T) {
  106. sigData := SignatureData{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0}
  107. expected := "0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400"
  108. assert.Equal(t, sigData.String(), expected)
  109. }
  110. func TestMinVAALength(t *testing.T) {
  111. assert.Equal(t, minVAALength, 57)
  112. }
  113. func TestChainId_String(t *testing.T) {
  114. type test struct {
  115. input ChainID
  116. output string
  117. }
  118. tests := []test{
  119. {input: 0, output: "unset"},
  120. {input: 1, output: "solana"},
  121. {input: 2, output: "ethereum"},
  122. {input: 3, output: "terra"},
  123. {input: 4, output: "bsc"},
  124. {input: 5, output: "polygon"},
  125. {input: 6, output: "avalanche"},
  126. {input: 7, output: "oasis"},
  127. {input: 8, output: "algorand"},
  128. {input: 9, output: "aurora"},
  129. {input: 10, output: "fantom"},
  130. {input: 11, output: "karura"},
  131. {input: 12, output: "acala"},
  132. {input: 13, output: "klaytn"},
  133. {input: 14, output: "celo"},
  134. {input: 16, output: "moonbeam"},
  135. {input: 17, output: "neon"},
  136. {input: 18, output: "terra2"},
  137. {input: 19, output: "injective"},
  138. {input: 10001, output: "ethereum-ropsten"},
  139. }
  140. for _, tc := range tests {
  141. t.Run(tc.output, func(t *testing.T) {
  142. assert.Equal(t, ChainID(tc.input).String(), tc.output)
  143. })
  144. }
  145. }
  146. func getVaa() VAA {
  147. var payload = []byte{97, 97, 97, 97, 97, 97}
  148. var governanceEmitter = Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}
  149. return VAA{
  150. Version: uint8(1),
  151. GuardianSetIndex: uint32(1),
  152. Signatures: []*Signature{},
  153. Timestamp: time.Unix(0, 0),
  154. Nonce: uint32(1),
  155. Sequence: uint64(1),
  156. ConsistencyLevel: uint8(32),
  157. EmitterChain: ChainIDSolana,
  158. EmitterAddress: governanceEmitter,
  159. Payload: payload,
  160. }
  161. }
  162. func TestAddSignature(t *testing.T) {
  163. vaa := getVaa()
  164. // Generate a random private key to sign with
  165. key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  166. assert.Equal(t, []*Signature{}, vaa.Signatures)
  167. // Add a signature and make sure it's added
  168. vaa.AddSignature(key, 0)
  169. assert.Equal(t, len(vaa.Signatures), 1)
  170. }
  171. func TestSerializeBody(t *testing.T) {
  172. vaa := getVaa()
  173. expected := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61}
  174. assert.Equal(t, vaa.serializeBody(), expected)
  175. }
  176. func TestSigningBody(t *testing.T) {
  177. vaa := getVaa()
  178. expected := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61}
  179. assert.Equal(t, vaa.signingBody(), expected)
  180. }
  181. func TestSigningMsg(t *testing.T) {
  182. vaa := getVaa()
  183. expected := common.HexToHash("4fae136bb1fd782fe1b5180ba735cdc83bcece3f9b7fd0e5e35300a61c8acd8f")
  184. assert.Equal(t, vaa.SigningMsg(), expected)
  185. }
  186. func TestMessageID(t *testing.T) {
  187. vaa := getVaa()
  188. expected := "1/0000000000000000000000000000000000000000000000000000000000000004/1"
  189. assert.Equal(t, vaa.MessageID(), expected)
  190. }
  191. func TestHexDigest(t *testing.T) {
  192. vaa := getVaa()
  193. expected := "4fae136bb1fd782fe1b5180ba735cdc83bcece3f9b7fd0e5e35300a61c8acd8f"
  194. assert.Equal(t, vaa.HexDigest(), expected)
  195. }
  196. func TestMarshal(t *testing.T) {
  197. expectedBytes := []byte{0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61}
  198. vaa := getVaa()
  199. marshalBytes, err := vaa.Marshal()
  200. assert.Nil(t, err)
  201. assert.Equal(t, expectedBytes, marshalBytes)
  202. }
  203. func TestUnmarshal(t *testing.T) {
  204. vaaBytes := []byte{0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61}
  205. vaa1 := getVaa()
  206. vaa2, err := Unmarshal(vaaBytes)
  207. assert.Nil(t, err)
  208. assert.Equal(t, &vaa1, vaa2)
  209. }
  210. func TestUnmarshalTooBig(t *testing.T) {
  211. vaa := getVaa()
  212. // Overwrite an oversized payload for the VAA that we cannot unmarshal
  213. var payload []byte
  214. for i := 0; i < 2000; i++ {
  215. payload = append(payload, 'a')
  216. }
  217. vaa.Payload = payload
  218. // Let's marshal the VAA to bytes to unmarshaled
  219. marshalBytes, err := vaa.Marshal()
  220. assert.Nil(t, err)
  221. // Let's now unmarshal the oversized VAA and cause it to panic
  222. vaa2, err2 := Unmarshal(marshalBytes)
  223. assert.Nil(t, err2)
  224. // Marshal the VAA
  225. marshalBytes2, err3 := vaa2.Marshal()
  226. assert.Nil(t, err3)
  227. // Verify that it's truncated at to 1057 (57 byte header + 1000 byte payload)
  228. assert.Equal(t, marshalBytes[:1057], marshalBytes2)
  229. }
  230. func TestVerifySignatures(t *testing.T) {
  231. // Generate some random private keys to sign with
  232. privKey1, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  233. privKey2, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  234. privKey3, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  235. privKey4, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  236. // Give a fixed order of trusted addresses
  237. addrs := []common.Address{}
  238. addrs = append(addrs, crypto.PubkeyToAddress(privKey1.PublicKey))
  239. addrs = append(addrs, crypto.PubkeyToAddress(privKey2.PublicKey))
  240. addrs = append(addrs, crypto.PubkeyToAddress(privKey3.PublicKey))
  241. type test struct {
  242. label string
  243. keyOrder []*ecdsa.PrivateKey
  244. addrs []common.Address
  245. indexOrder []uint8
  246. result bool
  247. }
  248. tests := []test{
  249. {label: "NoSignerZero",
  250. keyOrder: []*ecdsa.PrivateKey{},
  251. addrs: addrs,
  252. indexOrder: []uint8{0},
  253. result: true},
  254. {label: "NoSignerOne",
  255. keyOrder: []*ecdsa.PrivateKey{},
  256. addrs: addrs,
  257. indexOrder: []uint8{1},
  258. result: true},
  259. {label: "SingleZero",
  260. keyOrder: []*ecdsa.PrivateKey{privKey1},
  261. addrs: addrs,
  262. indexOrder: []uint8{0},
  263. result: true},
  264. {label: "RogueSingleOne",
  265. keyOrder: []*ecdsa.PrivateKey{privKey4},
  266. addrs: addrs,
  267. indexOrder: []uint8{0},
  268. result: false},
  269. {label: "RogueSingleZero",
  270. keyOrder: []*ecdsa.PrivateKey{privKey4},
  271. addrs: addrs,
  272. indexOrder: []uint8{0},
  273. result: false},
  274. {label: "SingleOne",
  275. keyOrder: []*ecdsa.PrivateKey{privKey1},
  276. addrs: addrs,
  277. indexOrder: []uint8{0},
  278. result: true},
  279. {label: "MultiUniqSignerMonotonicIndex",
  280. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  281. addrs: addrs,
  282. indexOrder: []uint8{0, 1, 2},
  283. result: true},
  284. {label: "MultiMisOrderedSignerMonotonicIndex",
  285. keyOrder: []*ecdsa.PrivateKey{privKey3, privKey2, privKey1},
  286. addrs: addrs,
  287. indexOrder: []uint8{0, 1, 2}, result: false},
  288. {label: "MultiUniqSignerNonMonotonic",
  289. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  290. addrs: addrs,
  291. indexOrder: []uint8{0, 2, 1},
  292. result: false},
  293. {label: "MultiUniqSignerFullSameIndex0",
  294. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  295. addrs: addrs,
  296. indexOrder: []uint8{0, 0, 0},
  297. result: false},
  298. {label: "MultiUniqSignerFullSameIndex1",
  299. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  300. addrs: addrs,
  301. indexOrder: []uint8{0, 0, 0},
  302. result: false},
  303. {label: "MultiUniqSignerPartialSameIndex",
  304. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  305. addrs: addrs,
  306. indexOrder: []uint8{0, 1, 1},
  307. result: false},
  308. {label: "MultiSameSignerPartialSameIndex",
  309. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey2},
  310. addrs: addrs,
  311. indexOrder: []uint8{0, 1, 1},
  312. result: false},
  313. {label: "MultiSameSignerNonMonotonic",
  314. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey2},
  315. addrs: addrs,
  316. indexOrder: []uint8{0, 2, 1},
  317. result: false},
  318. {label: "MultiSameSignerFullSameIndex",
  319. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey1, privKey1},
  320. addrs: addrs,
  321. indexOrder: []uint8{0, 0, 0},
  322. result: false},
  323. {label: "MultiSameSignerMonotonic",
  324. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey1, privKey1},
  325. addrs: addrs,
  326. indexOrder: []uint8{0, 1, 2},
  327. result: false},
  328. }
  329. for _, tc := range tests {
  330. t.Run(tc.label, func(t *testing.T) {
  331. vaa := getVaa()
  332. for i, key := range tc.keyOrder {
  333. vaa.AddSignature(key, tc.indexOrder[i])
  334. }
  335. assert.Equal(t, tc.result, vaa.VerifySignatures(tc.addrs))
  336. })
  337. }
  338. }
  339. func TestVerifySignaturesFuzz(t *testing.T) {
  340. // Generate some random trusted private keys to sign with
  341. privKey1, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  342. privKey2, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  343. privKey3, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  344. // Generate some random untrusted private keys to sign with
  345. privKey4, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  346. privKey5, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  347. privKey6, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  348. // Give a fixed order of trusted addresses (we intentionally omit privKey4, privKey5, privKey6)
  349. addrs := []common.Address{}
  350. addrs = append(addrs, crypto.PubkeyToAddress(privKey1.PublicKey))
  351. addrs = append(addrs, crypto.PubkeyToAddress(privKey2.PublicKey))
  352. addrs = append(addrs, crypto.PubkeyToAddress(privKey3.PublicKey))
  353. // key space for fuzz tests
  354. keys := []*ecdsa.PrivateKey{}
  355. keys = append(keys, privKey1)
  356. keys = append(keys, privKey2)
  357. keys = append(keys, privKey3)
  358. keys = append(keys, privKey4)
  359. keys = append(keys, privKey5)
  360. keys = append(keys, privKey6)
  361. // index space for fuzz tests
  362. indexes := []uint8{0, 1, 2, 3, 4, 5}
  363. type test struct {
  364. label string
  365. keyOrder []*ecdsa.PrivateKey
  366. addrs []common.Address
  367. indexOrder []uint8
  368. result bool
  369. }
  370. type allow struct {
  371. keyPair []*ecdsa.PrivateKey
  372. indexPair []uint8
  373. }
  374. // Known good cases where we should have a verified result for
  375. allows := []allow{
  376. {keyPair: []*ecdsa.PrivateKey{}, indexPair: []uint8{}},
  377. {keyPair: []*ecdsa.PrivateKey{privKey1}, indexPair: []uint8{0}},
  378. {keyPair: []*ecdsa.PrivateKey{privKey2}, indexPair: []uint8{1}},
  379. {keyPair: []*ecdsa.PrivateKey{privKey3}, indexPair: []uint8{2}},
  380. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey2}, indexPair: []uint8{0, 1}},
  381. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey3}, indexPair: []uint8{0, 2}},
  382. {keyPair: []*ecdsa.PrivateKey{privKey2, privKey3}, indexPair: []uint8{1, 2}},
  383. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3}, indexPair: []uint8{0, 1, 2}},
  384. }
  385. tests := []test{}
  386. keyPairs := [][]*ecdsa.PrivateKey{}
  387. indexPairs := [][]uint8{}
  388. // Build empty keyPair
  389. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{})
  390. // Build single keyPairs
  391. for _, key := range keys {
  392. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key})
  393. }
  394. // Build double keyPairs
  395. for _, key_i := range keys {
  396. for _, key_j := range keys {
  397. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key_i, key_j})
  398. }
  399. }
  400. // Build triple keyPairs
  401. for _, key_i := range keys {
  402. for _, key_j := range keys {
  403. for _, key_k := range keys {
  404. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key_i, key_j, key_k})
  405. }
  406. }
  407. }
  408. // Build empty indexPairs
  409. indexPairs = append(indexPairs, []uint8{})
  410. // Build single indexPairs
  411. for _, ind := range indexes {
  412. indexPairs = append(indexPairs, []uint8{ind})
  413. }
  414. // Build double indexPairs
  415. for _, ind_i := range indexes {
  416. for _, ind_j := range indexes {
  417. indexPairs = append(indexPairs, []uint8{ind_i, ind_j})
  418. }
  419. }
  420. // Build triple keyPairs
  421. for _, ind_i := range indexes {
  422. for _, ind_j := range indexes {
  423. for _, ind_k := range indexes {
  424. indexPairs = append(indexPairs, []uint8{ind_i, ind_j, ind_k})
  425. }
  426. }
  427. }
  428. // Build out the fuzzTest cases
  429. for _, keyPair := range keyPairs {
  430. for _, indexPair := range indexPairs {
  431. if len(keyPair) == len(indexPair) {
  432. result := false
  433. for _, allow := range allows {
  434. if reflect.DeepEqual(allow.indexPair, indexPair) && reflect.DeepEqual(allow.keyPair, keyPair) {
  435. result = true
  436. break
  437. }
  438. }
  439. test := test{label: "A", keyOrder: keyPair, addrs: addrs, indexOrder: indexPair, result: result}
  440. tests = append(tests, test)
  441. }
  442. }
  443. }
  444. // Run the fuzzTest cases
  445. for _, tc := range tests {
  446. t.Run(tc.label, func(t *testing.T) {
  447. vaa := getVaa()
  448. for i, key := range tc.keyOrder {
  449. vaa.AddSignature(key, tc.indexOrder[i])
  450. }
  451. /* Fuzz Debugging
  452. * Tell us what keys and indexes were used (for debug when/if we have a failure case)
  453. */
  454. if vaa.VerifySignatures(tc.addrs) != tc.result {
  455. if len(tc.keyOrder) == 0 {
  456. t.Logf("Key Order %v\n", tc.keyOrder)
  457. } else {
  458. keyIndex := []uint8{}
  459. for i, key_i := range keys {
  460. for _, key_k := range tc.keyOrder {
  461. if key_i == key_k {
  462. keyIndex = append(keyIndex, uint8(i))
  463. }
  464. }
  465. }
  466. t.Logf("Key Order %v\n", keyIndex)
  467. }
  468. t.Logf("Index Order %v\n", tc.indexOrder)
  469. }
  470. assert.Equal(t, tc.result, vaa.VerifySignatures(tc.addrs))
  471. })
  472. }
  473. }
  474. func TestStringToAddress(t *testing.T) {
  475. type Test struct {
  476. label string
  477. rawAddr string
  478. addr Address
  479. errString string
  480. }
  481. tests := []Test{
  482. {label: "simple",
  483. rawAddr: "0000000000000000000000000000000000000000000000000000000000000004",
  484. addr: Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
  485. errString: ""},
  486. {label: "zero-padding",
  487. rawAddr: "04",
  488. addr: Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
  489. errString: ""},
  490. {label: "trim-0x", rawAddr: "0x04",
  491. addr: Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
  492. errString: ""},
  493. {label: "20byte eth-style address", rawAddr: "0x0290FB167208Af455bB137780163b7B7a9a10C16",
  494. addr: Address{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x90, 0xfb, 0x16, 0x72, 0x8, 0xaf, 0x45, 0x5b, 0xb1, 0x37, 0x78, 0x1, 0x63, 0xb7, 0xb7, 0xa9, 0xa1, 0xc, 0x16},
  495. errString: ""},
  496. {label: "too long",
  497. rawAddr: "0x0000000000000000000000000000000000000000000000000000000000000000000004",
  498. errString: "value must be no more than 32 bytes"},
  499. {label: "too short",
  500. rawAddr: "4",
  501. errString: "value must be at least 1 byte"},
  502. {label: "empty string",
  503. rawAddr: "",
  504. errString: "value must be at least 1 byte"},
  505. }
  506. for _, tc := range tests {
  507. t.Run(string(tc.label), func(t *testing.T) {
  508. addr, err := StringToAddress(tc.rawAddr)
  509. if len(tc.errString) == 0 {
  510. assert.NoError(t, err)
  511. assert.Equal(t, tc.addr, addr)
  512. } else {
  513. assert.Equal(t, tc.errString, err.Error())
  514. }
  515. })
  516. }
  517. }
  518. func TestDecodeTransferPayloadHdr(t *testing.T) {
  519. type Test struct {
  520. label string
  521. vaa string
  522. payloadType uint8
  523. emitterChainId ChainID
  524. emitterAddr string
  525. originChain ChainID
  526. originAddress string
  527. targetChain ChainID
  528. targetAddress string
  529. amount int64
  530. errString string
  531. }
  532. tests := []Test{
  533. {label: "valid vaa",
  534. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f01000000000000000000000000000000000000000000000000000000002b369f40000000000000000000000000ddb64fe46a91d46ee29420539fc25fd07c5fea3e000221c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f000010000000000000000000000000000000000000000000000000000000000000000",
  535. payloadType: 1,
  536. emitterChainId: ChainIDEthereum,
  537. emitterAddr: "0000000000000000000000000290FB167208Af455bB137780163b7B7a9a10C16",
  538. originChain: ChainIDEthereum,
  539. originAddress: "000000000000000000000000DDb64fE46a91D46ee29420539FC25FD07c5FEa3E",
  540. targetChain: ChainIDSolana,
  541. targetAddress: "21c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f0",
  542. amount: 725000000,
  543. errString: "",
  544. },
  545. {label: "unsupported payload type",
  546. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f02000000000000000000000000000000000000000000000000000000002b369f40000000000000000000000000ddb64fe46a91d46ee29420539fc25fd07c5fea3e000221c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f000010000000000000000000000000000000000000000000000000000000000000000",
  547. errString: "unsupported payload type",
  548. },
  549. {label: "buffer too short",
  550. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f01",
  551. errString: "buffer too short",
  552. },
  553. {label: "empty string",
  554. vaa: "",
  555. errString: "VAA is too short",
  556. },
  557. }
  558. for _, tc := range tests {
  559. t.Run(string(tc.label), func(t *testing.T) {
  560. data, err := hex.DecodeString(tc.vaa)
  561. assert.NoError(t, err)
  562. vaa, err := Unmarshal(data)
  563. if err != nil {
  564. assert.Equal(t, tc.errString, err.Error())
  565. } else {
  566. assert.NoError(t, err)
  567. assert.NotNil(t, vaa)
  568. if len(tc.errString) == 0 {
  569. expectedEmitterAddr, err := StringToAddress(tc.emitterAddr)
  570. assert.NoError(t, err)
  571. expectedOriginAddress, err := StringToAddress(tc.originAddress)
  572. assert.NoError(t, err)
  573. expectedTargetAddress, err := StringToAddress(tc.targetAddress)
  574. assert.NoError(t, err)
  575. expectedAmount := big.NewInt(tc.amount)
  576. assert.Equal(t, tc.emitterChainId, vaa.EmitterChain)
  577. assert.Equal(t, expectedEmitterAddr, vaa.EmitterAddress)
  578. assert.Equal(t, 133, len(vaa.Payload))
  579. payload, err := DecodeTransferPayloadHdr(vaa.Payload)
  580. assert.NoError(t, err)
  581. assert.Equal(t, tc.payloadType, payload.Type)
  582. assert.Equal(t, tc.originChain, payload.OriginChain)
  583. assert.Equal(t, expectedOriginAddress, payload.OriginAddress)
  584. assert.Equal(t, tc.targetChain, payload.TargetChain)
  585. assert.Equal(t, expectedTargetAddress, payload.TargetAddress)
  586. assert.Equal(t, expectedAmount.Cmp(payload.Amount), 0)
  587. } else {
  588. _, err = DecodeTransferPayloadHdr(vaa.Payload)
  589. assert.NotNil(t, err)
  590. assert.Equal(t, tc.errString, err.Error())
  591. }
  592. }
  593. })
  594. }
  595. }
  596. func TestIsTransfer(t *testing.T) {
  597. type Test struct {
  598. label string
  599. payload []byte
  600. result bool
  601. }
  602. tests := []Test{
  603. {label: "empty", payload: []byte{}, result: false},
  604. {label: "non-valid payload", payload: []byte{0x0}, result: false},
  605. {label: "payload 1", payload: []byte{0x1}, result: true},
  606. {label: "payload 2", payload: []byte{0x2}, result: false},
  607. {label: "payload 3", payload: []byte{0x3}, result: true},
  608. {label: "payload 4", payload: []byte{0x4}, result: false},
  609. }
  610. for _, tc := range tests {
  611. t.Run(string(tc.label), func(t *testing.T) {
  612. assert.Equal(t, tc.result, IsTransfer(tc.payload))
  613. })
  614. }
  615. }