structs_test.go 25 KB

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