structs_test.go 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. package vaa
  2. import (
  3. "bytes"
  4. "crypto/ecdsa"
  5. "crypto/elliptic"
  6. "crypto/rand"
  7. "encoding/binary"
  8. "encoding/hex"
  9. "encoding/json"
  10. "errors"
  11. "fmt"
  12. "math/big"
  13. "reflect"
  14. "testing"
  15. "time"
  16. "github.com/ethereum/go-ethereum/common"
  17. "github.com/ethereum/go-ethereum/crypto"
  18. "github.com/stretchr/testify/assert"
  19. "github.com/stretchr/testify/require"
  20. )
  21. func TestChainIDFromString(t *testing.T) {
  22. type test struct {
  23. input string
  24. output ChainID
  25. }
  26. // Positive Test Cases
  27. p_tests := []test{
  28. {input: "solana", output: ChainIDSolana},
  29. {input: "ethereum", output: ChainIDEthereum},
  30. {input: "terra", output: ChainIDTerra},
  31. {input: "bsc", output: ChainIDBSC},
  32. {input: "polygon", output: ChainIDPolygon},
  33. {input: "avalanche", output: ChainIDAvalanche},
  34. {input: "oasis", output: ChainIDOasis},
  35. {input: "algorand", output: ChainIDAlgorand},
  36. {input: "aptos", output: ChainIDAptos},
  37. {input: "sui", output: ChainIDSui},
  38. {input: "near", output: ChainIDNear},
  39. {input: "aurora", output: ChainIDAurora},
  40. {input: "fantom", output: ChainIDFantom},
  41. {input: "karura", output: ChainIDKarura},
  42. {input: "acala", output: ChainIDAcala},
  43. {input: "klaytn", output: ChainIDKlaytn},
  44. {input: "celo", output: ChainIDCelo},
  45. {input: "moonbeam", output: ChainIDMoonbeam},
  46. {input: "terra2", output: ChainIDTerra2},
  47. {input: "injective", output: ChainIDInjective},
  48. {input: "osmosis", output: ChainIDOsmosis},
  49. {input: "arbitrum", output: ChainIDArbitrum},
  50. {input: "pythnet", output: ChainIDPythNet},
  51. {input: "optimism", output: ChainIDOptimism},
  52. {input: "gnosis", output: ChainIDGnosis},
  53. {input: "xpla", output: ChainIDXpla},
  54. {input: "btc", output: ChainIDBtc},
  55. {input: "base", output: ChainIDBase},
  56. {input: "sei", output: ChainIDSei},
  57. {input: "rootstock", output: ChainIDRootstock},
  58. {input: "scroll", output: ChainIDScroll},
  59. {input: "mantle", output: ChainIDMantle},
  60. {input: "blast", output: ChainIDBlast},
  61. {input: "wormchain", output: ChainIDWormchain},
  62. {input: "cosmoshub", output: ChainIDCosmoshub},
  63. {input: "evmos", output: ChainIDEvmos},
  64. {input: "kujira", output: ChainIDKujira},
  65. {input: "neutron", output: ChainIDNeutron},
  66. {input: "celestia", output: ChainIDCelestia},
  67. {input: "stargaze", output: ChainIDStargaze},
  68. {input: "seda", output: ChainIDSeda},
  69. {input: "dymension", output: ChainIDDymension},
  70. {input: "sepolia", output: ChainIDSepolia},
  71. {input: "arbitrum_sepolia", output: ChainIDArbitrumSepolia},
  72. {input: "base_sepolia", output: ChainIDBaseSepolia},
  73. {input: "optimism_sepolia", output: ChainIDOptimismSepolia},
  74. {input: "holesky", output: ChainIDHolesky},
  75. {input: "polygon_sepolia", output: ChainIDPolygonSepolia},
  76. {input: "Solana", output: ChainIDSolana},
  77. {input: "Ethereum", output: ChainIDEthereum},
  78. {input: "Terra", output: ChainIDTerra},
  79. {input: "Bsc", output: ChainIDBSC},
  80. {input: "Polygon", output: ChainIDPolygon},
  81. {input: "Avalanche", output: ChainIDAvalanche},
  82. {input: "Oasis", output: ChainIDOasis},
  83. {input: "Algorand", output: ChainIDAlgorand},
  84. {input: "Aptos", output: ChainIDAptos},
  85. {input: "Sui", output: ChainIDSui},
  86. {input: "Near", output: ChainIDNear},
  87. {input: "Aurora", output: ChainIDAurora},
  88. {input: "Fantom", output: ChainIDFantom},
  89. {input: "Karura", output: ChainIDKarura},
  90. {input: "Acala", output: ChainIDAcala},
  91. {input: "Klaytn", output: ChainIDKlaytn},
  92. {input: "Celo", output: ChainIDCelo},
  93. {input: "Moonbeam", output: ChainIDMoonbeam},
  94. {input: "Terra2", output: ChainIDTerra2},
  95. {input: "Injective", output: ChainIDInjective},
  96. {input: "Osmosis", output: ChainIDOsmosis},
  97. {input: "Arbitrum", output: ChainIDArbitrum},
  98. {input: "Optimism", output: ChainIDOptimism},
  99. {input: "Gnosis", output: ChainIDGnosis},
  100. {input: "Pythnet", output: ChainIDPythNet},
  101. {input: "XPLA", output: ChainIDXpla},
  102. {input: "BTC", output: ChainIDBtc},
  103. {input: "Base", output: ChainIDBase},
  104. {input: "Sei", output: ChainIDSei},
  105. {input: "Rootstock", output: ChainIDRootstock},
  106. {input: "Scroll", output: ChainIDScroll},
  107. {input: "Mantle", output: ChainIDMantle},
  108. {input: "Blast", output: ChainIDBlast},
  109. {input: "Wormchain", output: ChainIDWormchain},
  110. {input: "Cosmoshub", output: ChainIDCosmoshub},
  111. {input: "Evmos", output: ChainIDEvmos},
  112. {input: "Kujira", output: ChainIDKujira},
  113. {input: "Neutron", output: ChainIDNeutron},
  114. {input: "Celestia", output: ChainIDCelestia},
  115. {input: "Stargaze", output: ChainIDStargaze},
  116. {input: "Seda", output: ChainIDSeda},
  117. {input: "Sepolia", output: ChainIDSepolia},
  118. {input: "Arbitrum_Sepolia", output: ChainIDArbitrumSepolia},
  119. {input: "Base_Sepolia", output: ChainIDBaseSepolia},
  120. {input: "Optimism_Sepolia", output: ChainIDOptimismSepolia},
  121. {input: "Holesky", output: ChainIDHolesky},
  122. {input: "Polygon_Sepolia", output: ChainIDPolygonSepolia},
  123. }
  124. // Negative Test Cases
  125. n_tests := []test{
  126. {input: "Unknown", output: ChainIDUnset},
  127. }
  128. for _, tc := range p_tests {
  129. t.Run(tc.input, func(t *testing.T) {
  130. chainId, err := ChainIDFromString(tc.input)
  131. assert.Equal(t, tc.output, chainId)
  132. assert.NoError(t, err)
  133. })
  134. }
  135. for _, tc := range n_tests {
  136. t.Run(tc.input, func(t *testing.T) {
  137. chainId, err := ChainIDFromString(tc.input)
  138. assert.Equal(t, tc.output, chainId)
  139. assert.NotNil(t, err)
  140. })
  141. }
  142. }
  143. func TestAddress_MarshalJSON(t *testing.T) {
  144. 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}
  145. expected := "223030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303422"
  146. marshalJsonAddress, err := addr.MarshalJSON()
  147. assert.Equal(t, hex.EncodeToString(marshalJsonAddress), expected)
  148. assert.NoError(t, err)
  149. }
  150. func TestAddress_UnmarshalJSON(t *testing.T) {
  151. tests := []struct {
  152. name string
  153. address Address
  154. addressJSON string
  155. err error
  156. }{
  157. {
  158. name: "working",
  159. addressJSON: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16",
  160. address: 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},
  161. err: nil,
  162. },
  163. {
  164. name: "failure",
  165. addressJSON: "derp",
  166. address: Address{},
  167. err: hex.InvalidByteError(0x72),
  168. },
  169. }
  170. for _, testCase := range tests {
  171. t.Run(testCase.name, func(t *testing.T) {
  172. var unmarshalAddr Address
  173. err := unmarshalAddr.UnmarshalJSON([]byte(testCase.addressJSON))
  174. require.Equal(t, testCase.err, err)
  175. assert.Equal(t, testCase.address, unmarshalAddr)
  176. })
  177. }
  178. }
  179. func TestAddress_Unmarshal(t *testing.T) {
  180. addr, _ := StringToAddress("0x0290fb167208af455bb137780163b7b7a9a10c16")
  181. b, err := json.Marshal(addr)
  182. require.NoError(t, err)
  183. var unmarshalAddr Address
  184. err = json.Unmarshal(b, &unmarshalAddr)
  185. require.NoError(t, err)
  186. assert.Equal(t, addr, unmarshalAddr)
  187. }
  188. func TestAddress_UnmarshalEmptyBuffer(t *testing.T) {
  189. b := []byte{}
  190. var unmarshalAddr Address
  191. err := json.Unmarshal(b, &unmarshalAddr)
  192. require.Error(t, err)
  193. }
  194. func TestAddress_UnmarshalBufferTooShort(t *testing.T) {
  195. addr, _ := StringToAddress("0x0290fb167208af455bb137780163b7b7a9a10c16")
  196. b, err := json.Marshal(addr)
  197. require.NoError(t, err)
  198. var unmarshalAddr Address
  199. // Lop off the first byte, and it should fail.
  200. b1 := b[1:]
  201. err = json.Unmarshal(b1, &unmarshalAddr)
  202. assert.Error(t, err)
  203. // Lop off the last byte, and it should fail.
  204. b2 := b[0 : len(b)-1]
  205. err = json.Unmarshal(b2, &unmarshalAddr)
  206. assert.Error(t, err)
  207. }
  208. func TestAddress_String(t *testing.T) {
  209. 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}
  210. expected := "0000000000000000000000000000000000000000000000000000000000000004"
  211. assert.Equal(t, addr.String(), expected)
  212. }
  213. func TestAddress_Bytes(t *testing.T) {
  214. 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}
  215. 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}
  216. assert.Equal(t, addr.Bytes(), expected)
  217. }
  218. func TestSignatureData_MarshalJSON(t *testing.T) {
  219. 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}
  220. marshalJsonSigData, err := sigData.MarshalJSON()
  221. require.Nil(t, err)
  222. expected := "223030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303034303022"
  223. assert.Equal(t, hex.EncodeToString(marshalJsonSigData), expected)
  224. }
  225. func TestSignature_DataString(t *testing.T) {
  226. 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}
  227. expected := "0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400"
  228. assert.Equal(t, sigData.String(), expected)
  229. }
  230. func TestMinVAALength(t *testing.T) {
  231. assert.Equal(t, minVAALength, 57)
  232. }
  233. func TestChainId_String(t *testing.T) {
  234. type test struct {
  235. input ChainID
  236. output string
  237. }
  238. tests := []test{
  239. {input: 0, output: "unset"},
  240. {input: 1, output: "solana"},
  241. {input: 2, output: "ethereum"},
  242. {input: 3, output: "terra"},
  243. {input: 4, output: "bsc"},
  244. {input: 5, output: "polygon"},
  245. {input: 6, output: "avalanche"},
  246. {input: 7, output: "oasis"},
  247. {input: 8, output: "algorand"},
  248. {input: 9, output: "aurora"},
  249. {input: 10, output: "fantom"},
  250. {input: 11, output: "karura"},
  251. {input: 12, output: "acala"},
  252. {input: 13, output: "klaytn"},
  253. {input: 14, output: "celo"},
  254. {input: 15, output: "near"},
  255. {input: 16, output: "moonbeam"},
  256. {input: 18, output: "terra2"},
  257. {input: 19, output: "injective"},
  258. {input: 20, output: "osmosis"},
  259. {input: 21, output: "sui"},
  260. {input: 22, output: "aptos"},
  261. {input: 23, output: "arbitrum"},
  262. {input: 24, output: "optimism"},
  263. {input: 25, output: "gnosis"},
  264. {input: 26, output: "pythnet"},
  265. {input: 28, output: "xpla"},
  266. {input: 29, output: "btc"},
  267. {input: 30, output: "base"},
  268. {input: 32, output: "sei"},
  269. {input: 33, output: "rootstock"},
  270. {input: 34, output: "scroll"},
  271. {input: 35, output: "mantle"},
  272. {input: 36, output: "blast"},
  273. {input: 3104, output: "wormchain"},
  274. {input: 4000, output: "cosmoshub"},
  275. {input: 4001, output: "evmos"},
  276. {input: 4002, output: "kujira"},
  277. {input: 4003, output: "neutron"},
  278. {input: 4004, output: "celestia"},
  279. {input: 4005, output: "stargaze"},
  280. {input: 4006, output: "seda"},
  281. {input: 10002, output: "sepolia"},
  282. {input: 10003, output: "arbitrum_sepolia"},
  283. {input: 10004, output: "base_sepolia"},
  284. {input: 10005, output: "optimism_sepolia"},
  285. {input: 10006, output: "holesky"},
  286. {input: 10007, output: "polygon_sepolia"},
  287. {input: 10000, output: "unknown chain ID: 10000"},
  288. }
  289. for _, tc := range tests {
  290. t.Run(tc.output, func(t *testing.T) {
  291. assert.Equal(t, ChainID(tc.input).String(), tc.output)
  292. })
  293. }
  294. }
  295. func getVaa() VAA {
  296. var payload = []byte{97, 97, 97, 97, 97, 97}
  297. 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}
  298. return VAA{
  299. Version: uint8(1),
  300. GuardianSetIndex: uint32(1),
  301. Signatures: []*Signature{},
  302. Timestamp: time.Unix(0, 0),
  303. Nonce: uint32(1),
  304. Sequence: uint64(1),
  305. ConsistencyLevel: uint8(32),
  306. EmitterChain: ChainIDSolana,
  307. EmitterAddress: governanceEmitter,
  308. Payload: payload,
  309. }
  310. }
  311. func getEmptyPayloadVaa() VAA {
  312. var payload = []byte{}
  313. 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}
  314. return VAA{
  315. Version: uint8(1),
  316. GuardianSetIndex: uint32(1),
  317. Signatures: []*Signature{},
  318. Timestamp: time.Unix(0, 0),
  319. Nonce: uint32(1),
  320. Sequence: uint64(1),
  321. ConsistencyLevel: uint8(32),
  322. EmitterChain: ChainIDSolana,
  323. EmitterAddress: governanceEmitter,
  324. Payload: payload,
  325. }
  326. }
  327. func TestAddSignature(t *testing.T) {
  328. vaa := getVaa()
  329. // Generate a random private key to sign with
  330. key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  331. assert.Equal(t, []*Signature{}, vaa.Signatures)
  332. // Add a signature and make sure it's added
  333. vaa.AddSignature(key, 0)
  334. assert.Equal(t, len(vaa.Signatures), 1)
  335. }
  336. func TestSerializeBody(t *testing.T) {
  337. vaa := getVaa()
  338. 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}
  339. assert.Equal(t, vaa.serializeBody(), expected)
  340. }
  341. func TestSigningBody(t *testing.T) {
  342. vaa := getVaa()
  343. 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}
  344. assert.Equal(t, vaa.signingBody(), expected)
  345. }
  346. func TestSigningMsg(t *testing.T) {
  347. vaa := getVaa()
  348. expected := common.HexToHash("4fae136bb1fd782fe1b5180ba735cdc83bcece3f9b7fd0e5e35300a61c8acd8f")
  349. assert.Equal(t, vaa.SigningDigest(), expected)
  350. }
  351. func TestMessageID(t *testing.T) {
  352. vaa := getVaa()
  353. expected := "1/0000000000000000000000000000000000000000000000000000000000000004/1"
  354. assert.Equal(t, vaa.MessageID(), expected)
  355. }
  356. func TestHexDigest(t *testing.T) {
  357. vaa := getVaa()
  358. expected := "4fae136bb1fd782fe1b5180ba735cdc83bcece3f9b7fd0e5e35300a61c8acd8f"
  359. assert.Equal(t, vaa.HexDigest(), expected)
  360. }
  361. func TestMarshal(t *testing.T) {
  362. 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}
  363. vaa := getVaa()
  364. marshalBytes, err := vaa.Marshal()
  365. assert.Nil(t, err)
  366. assert.Equal(t, expectedBytes, marshalBytes)
  367. }
  368. func TestUnmarshal(t *testing.T) {
  369. 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}
  370. vaa1 := getVaa()
  371. vaa2, err := Unmarshal(vaaBytes)
  372. assert.Nil(t, err)
  373. assert.Equal(t, &vaa1, vaa2)
  374. }
  375. func TestUnmarshalNoPayload(t *testing.T) {
  376. 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}
  377. vaa1 := getEmptyPayloadVaa()
  378. vaa2, err := Unmarshal(vaaBytes)
  379. assert.Nil(t, err)
  380. assert.Equal(t, &vaa1, vaa2)
  381. }
  382. func TestUnmarshalBigPayload(t *testing.T) {
  383. vaa := getVaa()
  384. // Create a payload of more than 1000 bytes.
  385. var payload []byte
  386. for i := 0; i < 2000; i++ {
  387. ch := i % 255
  388. payload = append(payload, byte(ch))
  389. }
  390. vaa.Payload = payload
  391. marshalBytes, err := vaa.Marshal()
  392. require.NoError(t, err)
  393. vaa2, err := Unmarshal(marshalBytes)
  394. require.NoError(t, err)
  395. assert.Equal(t, vaa, *vaa2)
  396. }
  397. func FuzzUnmarshalBigPayload(f *testing.F) {
  398. f.Add([]byte{})
  399. f.Add([]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})
  400. f.Fuzz(func(t *testing.T, payload []byte) {
  401. vaa := getVaa()
  402. vaa.Payload = payload
  403. // It should always marshal
  404. marshalBytes, err := vaa.Marshal()
  405. require.NoError(t, err)
  406. // It should aways unmarshal
  407. vaa2, err := Unmarshal(marshalBytes)
  408. require.NoError(t, err)
  409. // The payload should not be lossy
  410. assert.Equal(t, vaa.Payload, payload)
  411. assert.Equal(t, vaa2.Payload, payload)
  412. // The marshal and unmarshal should always be the same
  413. assert.Equal(t, vaa, *vaa2)
  414. })
  415. }
  416. func TestVerifySignatures(t *testing.T) {
  417. // Generate some random private keys to sign with
  418. privKey1, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  419. privKey2, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  420. privKey3, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  421. privKey4, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  422. // Give a fixed order of trusted addresses
  423. addrs := []common.Address{}
  424. addrs = append(addrs, crypto.PubkeyToAddress(privKey1.PublicKey))
  425. addrs = append(addrs, crypto.PubkeyToAddress(privKey2.PublicKey))
  426. addrs = append(addrs, crypto.PubkeyToAddress(privKey3.PublicKey))
  427. type test struct {
  428. label string
  429. keyOrder []*ecdsa.PrivateKey
  430. addrs []common.Address
  431. indexOrder []uint8
  432. result bool
  433. }
  434. tests := []test{
  435. {label: "NoSignerZero",
  436. keyOrder: []*ecdsa.PrivateKey{},
  437. addrs: addrs,
  438. indexOrder: []uint8{0},
  439. result: true},
  440. {label: "NoSignerOne",
  441. keyOrder: []*ecdsa.PrivateKey{},
  442. addrs: addrs,
  443. indexOrder: []uint8{1},
  444. result: true},
  445. {label: "SingleZero",
  446. keyOrder: []*ecdsa.PrivateKey{privKey1},
  447. addrs: addrs,
  448. indexOrder: []uint8{0},
  449. result: true},
  450. {label: "RogueSingleOne",
  451. keyOrder: []*ecdsa.PrivateKey{privKey4},
  452. addrs: addrs,
  453. indexOrder: []uint8{0},
  454. result: false},
  455. {label: "RogueSingleZero",
  456. keyOrder: []*ecdsa.PrivateKey{privKey4},
  457. addrs: addrs,
  458. indexOrder: []uint8{0},
  459. result: false},
  460. {label: "SingleOne",
  461. keyOrder: []*ecdsa.PrivateKey{privKey1},
  462. addrs: addrs,
  463. indexOrder: []uint8{0},
  464. result: true},
  465. {label: "MultiUniqSignerMonotonicIndex",
  466. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  467. addrs: addrs,
  468. indexOrder: []uint8{0, 1, 2},
  469. result: true},
  470. {label: "MultiMisOrderedSignerMonotonicIndex",
  471. keyOrder: []*ecdsa.PrivateKey{privKey3, privKey2, privKey1},
  472. addrs: addrs,
  473. indexOrder: []uint8{0, 1, 2}, result: false},
  474. {label: "MultiUniqSignerNonMonotonic",
  475. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  476. addrs: addrs,
  477. indexOrder: []uint8{0, 2, 1},
  478. result: false},
  479. {label: "MultiUniqSignerFullSameIndex0",
  480. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  481. addrs: addrs,
  482. indexOrder: []uint8{0, 0, 0},
  483. result: false},
  484. {label: "MultiUniqSignerFullSameIndex1",
  485. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  486. addrs: addrs,
  487. indexOrder: []uint8{0, 0, 0},
  488. result: false},
  489. {label: "MultiUniqSignerPartialSameIndex",
  490. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3},
  491. addrs: addrs,
  492. indexOrder: []uint8{0, 1, 1},
  493. result: false},
  494. {label: "MultiSameSignerPartialSameIndex",
  495. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey2},
  496. addrs: addrs,
  497. indexOrder: []uint8{0, 1, 1},
  498. result: false},
  499. {label: "MultiSameSignerNonMonotonic",
  500. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey2, privKey2},
  501. addrs: addrs,
  502. indexOrder: []uint8{0, 2, 1},
  503. result: false},
  504. {label: "MultiSameSignerFullSameIndex",
  505. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey1, privKey1},
  506. addrs: addrs,
  507. indexOrder: []uint8{0, 0, 0},
  508. result: false},
  509. {label: "MultiSameSignerMonotonic",
  510. keyOrder: []*ecdsa.PrivateKey{privKey1, privKey1, privKey1},
  511. addrs: addrs,
  512. indexOrder: []uint8{0, 1, 2},
  513. result: false},
  514. }
  515. for _, tc := range tests {
  516. t.Run(tc.label, func(t *testing.T) {
  517. vaa := getVaa()
  518. for i, key := range tc.keyOrder {
  519. vaa.AddSignature(key, tc.indexOrder[i])
  520. }
  521. assert.Equal(t, tc.result, vaa.VerifySignatures(tc.addrs))
  522. })
  523. }
  524. }
  525. func TestVerifySignaturesFuzz(t *testing.T) {
  526. // Generate some random trusted private keys to sign with
  527. privKey1, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  528. privKey2, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  529. privKey3, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  530. // Generate some random untrusted private keys to sign with
  531. privKey4, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  532. privKey5, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  533. privKey6, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
  534. // Give a fixed order of trusted addresses (we intentionally omit privKey4, privKey5, privKey6)
  535. addrs := []common.Address{}
  536. addrs = append(addrs, crypto.PubkeyToAddress(privKey1.PublicKey))
  537. addrs = append(addrs, crypto.PubkeyToAddress(privKey2.PublicKey))
  538. addrs = append(addrs, crypto.PubkeyToAddress(privKey3.PublicKey))
  539. // key space for fuzz tests
  540. keys := []*ecdsa.PrivateKey{}
  541. keys = append(keys, privKey1)
  542. keys = append(keys, privKey2)
  543. keys = append(keys, privKey3)
  544. keys = append(keys, privKey4)
  545. keys = append(keys, privKey5)
  546. keys = append(keys, privKey6)
  547. // index space for fuzz tests
  548. indexes := []uint8{0, 1, 2, 3, 4, 5}
  549. type test struct {
  550. label string
  551. keyOrder []*ecdsa.PrivateKey
  552. addrs []common.Address
  553. indexOrder []uint8
  554. result bool
  555. }
  556. type allow struct {
  557. keyPair []*ecdsa.PrivateKey
  558. indexPair []uint8
  559. }
  560. // Known good cases where we should have a verified result for
  561. allows := []allow{
  562. {keyPair: []*ecdsa.PrivateKey{}, indexPair: []uint8{}},
  563. {keyPair: []*ecdsa.PrivateKey{privKey1}, indexPair: []uint8{0}},
  564. {keyPair: []*ecdsa.PrivateKey{privKey2}, indexPair: []uint8{1}},
  565. {keyPair: []*ecdsa.PrivateKey{privKey3}, indexPair: []uint8{2}},
  566. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey2}, indexPair: []uint8{0, 1}},
  567. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey3}, indexPair: []uint8{0, 2}},
  568. {keyPair: []*ecdsa.PrivateKey{privKey2, privKey3}, indexPair: []uint8{1, 2}},
  569. {keyPair: []*ecdsa.PrivateKey{privKey1, privKey2, privKey3}, indexPair: []uint8{0, 1, 2}},
  570. }
  571. tests := []test{}
  572. keyPairs := [][]*ecdsa.PrivateKey{}
  573. indexPairs := [][]uint8{}
  574. // Build empty keyPair
  575. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{})
  576. // Build single keyPairs
  577. for _, key := range keys {
  578. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key})
  579. }
  580. // Build double keyPairs
  581. for _, key_i := range keys {
  582. for _, key_j := range keys {
  583. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key_i, key_j})
  584. }
  585. }
  586. // Build triple keyPairs
  587. for _, key_i := range keys {
  588. for _, key_j := range keys {
  589. for _, key_k := range keys {
  590. keyPairs = append(keyPairs, []*ecdsa.PrivateKey{key_i, key_j, key_k})
  591. }
  592. }
  593. }
  594. // Build empty indexPairs
  595. indexPairs = append(indexPairs, []uint8{})
  596. // Build single indexPairs
  597. for _, ind := range indexes {
  598. indexPairs = append(indexPairs, []uint8{ind})
  599. }
  600. // Build double indexPairs
  601. for _, ind_i := range indexes {
  602. for _, ind_j := range indexes {
  603. indexPairs = append(indexPairs, []uint8{ind_i, ind_j})
  604. }
  605. }
  606. // Build triple keyPairs
  607. for _, ind_i := range indexes {
  608. for _, ind_j := range indexes {
  609. for _, ind_k := range indexes {
  610. indexPairs = append(indexPairs, []uint8{ind_i, ind_j, ind_k})
  611. }
  612. }
  613. }
  614. // Build out the fuzzTest cases
  615. for _, keyPair := range keyPairs {
  616. for _, indexPair := range indexPairs {
  617. if len(keyPair) == len(indexPair) {
  618. result := false
  619. for _, allow := range allows {
  620. if reflect.DeepEqual(allow.indexPair, indexPair) && reflect.DeepEqual(allow.keyPair, keyPair) {
  621. result = true
  622. break
  623. }
  624. }
  625. test := test{label: "A", keyOrder: keyPair, addrs: addrs, indexOrder: indexPair, result: result}
  626. tests = append(tests, test)
  627. }
  628. }
  629. }
  630. // Run the fuzzTest cases
  631. for _, tc := range tests {
  632. t.Run(tc.label, func(t *testing.T) {
  633. vaa := getVaa()
  634. for i, key := range tc.keyOrder {
  635. vaa.AddSignature(key, tc.indexOrder[i])
  636. }
  637. /* Fuzz Debugging
  638. * Tell us what keys and indexes were used (for debug when/if we have a failure case)
  639. */
  640. if vaa.VerifySignatures(tc.addrs) != tc.result {
  641. if len(tc.keyOrder) == 0 {
  642. t.Logf("Key Order %v\n", tc.keyOrder)
  643. } else {
  644. keyIndex := []uint8{}
  645. for i, key_i := range keys {
  646. for _, key_k := range tc.keyOrder {
  647. if key_i == key_k {
  648. keyIndex = append(keyIndex, uint8(i))
  649. }
  650. }
  651. }
  652. t.Logf("Key Order %v\n", keyIndex)
  653. }
  654. t.Logf("Index Order %v\n", tc.indexOrder)
  655. }
  656. assert.Equal(t, tc.result, vaa.VerifySignatures(tc.addrs))
  657. })
  658. }
  659. }
  660. func TestStringToAddress(t *testing.T) {
  661. type Test struct {
  662. label string
  663. rawAddr string
  664. addr Address
  665. errString string
  666. }
  667. tests := []Test{
  668. {label: "simple",
  669. rawAddr: "0000000000000000000000000000000000000000000000000000000000000004",
  670. 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},
  671. errString: ""},
  672. {label: "zero-padding",
  673. rawAddr: "04",
  674. 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},
  675. errString: ""},
  676. {label: "trim-0x", rawAddr: "0x04",
  677. 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},
  678. errString: ""},
  679. {label: "20byte eth-style address", rawAddr: "0x0290FB167208Af455bB137780163b7B7a9a10C16",
  680. 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},
  681. errString: ""},
  682. {label: "too long",
  683. rawAddr: "0x0000000000000000000000000000000000000000000000000000000000000000000004",
  684. errString: "value must be no more than 32 bytes"},
  685. {label: "too short",
  686. rawAddr: "4",
  687. errString: "value must be at least 1 byte"},
  688. {label: "empty string",
  689. rawAddr: "",
  690. errString: "value must be at least 1 byte"},
  691. }
  692. for _, tc := range tests {
  693. t.Run(string(tc.label), func(t *testing.T) {
  694. addr, err := StringToAddress(tc.rawAddr)
  695. if len(tc.errString) == 0 {
  696. assert.NoError(t, err)
  697. assert.Equal(t, tc.addr, addr)
  698. } else {
  699. assert.Equal(t, tc.errString, err.Error())
  700. }
  701. })
  702. }
  703. }
  704. func TestBytesToAddress(t *testing.T) {
  705. addrStr := "0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585"
  706. expectedAddr, err := StringToAddress(addrStr)
  707. assert.NoError(t, err)
  708. addrBytes, err := hex.DecodeString(addrStr)
  709. assert.NoError(t, err)
  710. addr, err := BytesToAddress(addrBytes)
  711. assert.NoError(t, err)
  712. assert.Equal(t, expectedAddr, addr)
  713. // More than 32 bytes should generate an error.
  714. tooLongAddrBytes, err := hex.DecodeString("0000" + addrStr)
  715. assert.NoError(t, err)
  716. _, err = BytesToAddress(tooLongAddrBytes)
  717. assert.NotNil(t, err)
  718. assert.Equal(t, "value must be no more than 32 bytes", err.Error())
  719. // Less than 32 bytes should get left padded with zeros.
  720. shortAddr, err := BytesToAddress(addrBytes[4:])
  721. assert.NoError(t, err)
  722. assert.Equal(t, expectedAddr, shortAddr)
  723. }
  724. func TestDecodeTransferPayloadHdr(t *testing.T) {
  725. type Test struct {
  726. label string
  727. vaa string
  728. payloadType uint8
  729. emitterChainId ChainID
  730. emitterAddr string
  731. originChain ChainID
  732. originAddress string
  733. targetChain ChainID
  734. targetAddress string
  735. amount int64
  736. errString string
  737. }
  738. tests := []Test{
  739. {label: "valid vaa",
  740. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f01000000000000000000000000000000000000000000000000000000002b369f40000000000000000000000000ddb64fe46a91d46ee29420539fc25fd07c5fea3e000221c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f000010000000000000000000000000000000000000000000000000000000000000000",
  741. payloadType: 1,
  742. emitterChainId: ChainIDEthereum,
  743. emitterAddr: "0000000000000000000000000290FB167208Af455bB137780163b7B7a9a10C16",
  744. originChain: ChainIDEthereum,
  745. originAddress: "000000000000000000000000DDb64fE46a91D46ee29420539FC25FD07c5FEa3E",
  746. targetChain: ChainIDSolana,
  747. targetAddress: "21c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f0",
  748. amount: 725000000,
  749. errString: "",
  750. },
  751. {label: "unsupported payload type",
  752. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f02000000000000000000000000000000000000000000000000000000002b369f40000000000000000000000000ddb64fe46a91d46ee29420539fc25fd07c5fea3e000221c175fcd8e3a19fe2e0deae96534f0f4e6a896f4df0e3ec5345fe27ac3f63f000010000000000000000000000000000000000000000000000000000000000000000",
  753. errString: "unsupported payload type",
  754. },
  755. {label: "buffer too short",
  756. vaa: "01000000000100e424aef95296cb0f2185f351086c7c0b9cd031d1288f0537d04ab20d5fc709416224b2bd9a8010a81988aa9cb38b378eb915f88b67e32a765928d948dc02077e00000102584a8d000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000f0f01",
  757. errString: "buffer too short",
  758. },
  759. {label: "empty string",
  760. vaa: "",
  761. errString: "VAA is too short",
  762. },
  763. }
  764. for _, tc := range tests {
  765. t.Run(string(tc.label), func(t *testing.T) {
  766. data, err := hex.DecodeString(tc.vaa)
  767. assert.NoError(t, err)
  768. vaa, err := Unmarshal(data)
  769. if err != nil {
  770. assert.Equal(t, tc.errString, err.Error())
  771. } else {
  772. assert.NoError(t, err)
  773. assert.NotNil(t, vaa)
  774. if len(tc.errString) == 0 {
  775. expectedEmitterAddr, err := StringToAddress(tc.emitterAddr)
  776. assert.NoError(t, err)
  777. expectedOriginAddress, err := StringToAddress(tc.originAddress)
  778. assert.NoError(t, err)
  779. expectedTargetAddress, err := StringToAddress(tc.targetAddress)
  780. assert.NoError(t, err)
  781. expectedAmount := big.NewInt(tc.amount)
  782. assert.Equal(t, tc.emitterChainId, vaa.EmitterChain)
  783. assert.Equal(t, expectedEmitterAddr, vaa.EmitterAddress)
  784. assert.Equal(t, 133, len(vaa.Payload))
  785. payload, err := DecodeTransferPayloadHdr(vaa.Payload)
  786. assert.NoError(t, err)
  787. assert.Equal(t, tc.payloadType, payload.Type)
  788. assert.Equal(t, tc.originChain, payload.OriginChain)
  789. assert.Equal(t, expectedOriginAddress, payload.OriginAddress)
  790. assert.Equal(t, tc.targetChain, payload.TargetChain)
  791. assert.Equal(t, expectedTargetAddress, payload.TargetAddress)
  792. assert.Equal(t, expectedAmount.Cmp(payload.Amount), 0)
  793. } else {
  794. _, err = DecodeTransferPayloadHdr(vaa.Payload)
  795. assert.NotNil(t, err)
  796. assert.Equal(t, tc.errString, err.Error())
  797. }
  798. }
  799. })
  800. }
  801. }
  802. func TestIsTransfer(t *testing.T) {
  803. type Test struct {
  804. label string
  805. payload []byte
  806. result bool
  807. }
  808. tests := []Test{
  809. {label: "empty", payload: []byte{}, result: false},
  810. {label: "non-valid payload", payload: []byte{0x0}, result: false},
  811. {label: "payload 1", payload: []byte{0x1}, result: true},
  812. {label: "payload 2", payload: []byte{0x2}, result: false},
  813. {label: "payload 3", payload: []byte{0x3}, result: true},
  814. {label: "payload 4", payload: []byte{0x4}, result: false},
  815. }
  816. for _, tc := range tests {
  817. t.Run(string(tc.label), func(t *testing.T) {
  818. assert.Equal(t, tc.result, IsTransfer(tc.payload))
  819. })
  820. }
  821. }
  822. func TestUnmarshalBody(t *testing.T) {
  823. addr, _ := StringToAddress("0x0290fb167208af455bb137780163b7b7a9a10c16")
  824. testPayload := []byte("Hi")
  825. tests := []struct {
  826. name string
  827. data []byte
  828. vaa *VAA
  829. err error
  830. expectedVAA *VAA
  831. dataFunc func() []byte
  832. }{
  833. {
  834. name: "invalid_timestamp",
  835. dataFunc: func() []byte {
  836. return []byte("Hi")
  837. },
  838. err: fmt.Errorf("failed to read timestamp: %w", errors.New("unexpected EOF")),
  839. },
  840. {
  841. name: "invalid_nonce",
  842. err: fmt.Errorf("failed to read nonce: %w", errors.New("EOF")),
  843. vaa: &VAA{},
  844. dataFunc: func() []byte {
  845. buf := new(bytes.Buffer)
  846. MustWrite(buf, binary.BigEndian, uint32(time.Now().Unix()))
  847. return buf.Bytes()
  848. },
  849. },
  850. {
  851. name: "invalid_emmitter_chain",
  852. err: fmt.Errorf("failed to read emitter chain: %w", errors.New("EOF")),
  853. vaa: &VAA{},
  854. dataFunc: func() []byte {
  855. buf := new(bytes.Buffer)
  856. MustWrite(buf, binary.BigEndian, uint32(time.Now().Unix()))
  857. MustWrite(buf, binary.BigEndian, uint32(123))
  858. return buf.Bytes()
  859. },
  860. },
  861. {
  862. name: "invalid_emmitter_address",
  863. err: fmt.Errorf("failed to read emitter address [0]: %w", errors.New("EOF")),
  864. vaa: &VAA{},
  865. dataFunc: func() []byte {
  866. buf := new(bytes.Buffer)
  867. MustWrite(buf, binary.BigEndian, uint32(time.Now().Unix()))
  868. MustWrite(buf, binary.BigEndian, uint32(123))
  869. MustWrite(buf, binary.BigEndian, ChainIDPythNet)
  870. return buf.Bytes()
  871. },
  872. },
  873. {
  874. name: "invalid_sequence_number",
  875. err: fmt.Errorf("failed to read sequence: %w", errors.New("EOF")),
  876. vaa: &VAA{},
  877. dataFunc: func() []byte {
  878. buf := new(bytes.Buffer)
  879. MustWrite(buf, binary.BigEndian, uint32(time.Now().Unix()))
  880. MustWrite(buf, binary.BigEndian, uint32(123))
  881. MustWrite(buf, binary.BigEndian, ChainIDBSC)
  882. buf.Write(addr[:])
  883. return buf.Bytes()
  884. },
  885. },
  886. {
  887. name: "invalid_consistency_level",
  888. err: fmt.Errorf("failed to read commitment: %w", errors.New("EOF")),
  889. vaa: &VAA{},
  890. dataFunc: func() []byte {
  891. buf := new(bytes.Buffer)
  892. MustWrite(buf, binary.BigEndian, uint32(time.Now().Unix()))
  893. MustWrite(buf, binary.BigEndian, uint32(123))
  894. MustWrite(buf, binary.BigEndian, ChainIDBSC)
  895. buf.Write(addr[:])
  896. MustWrite(buf, binary.BigEndian, uint64(42))
  897. return buf.Bytes()
  898. },
  899. },
  900. {
  901. name: "has_payload",
  902. err: nil,
  903. vaa: &VAA{},
  904. expectedVAA: &VAA{
  905. Nonce: uint32(123),
  906. Sequence: uint64(42),
  907. ConsistencyLevel: uint8(1),
  908. EmitterChain: ChainIDBSC,
  909. Timestamp: time.Unix(0, 0),
  910. EmitterAddress: addr,
  911. Payload: testPayload,
  912. },
  913. dataFunc: func() []byte {
  914. buf := new(bytes.Buffer)
  915. MustWrite(buf, binary.BigEndian, uint32(0))
  916. MustWrite(buf, binary.BigEndian, uint32(123))
  917. MustWrite(buf, binary.BigEndian, ChainIDBSC)
  918. buf.Write(addr[:])
  919. MustWrite(buf, binary.BigEndian, uint64(42))
  920. MustWrite(buf, binary.BigEndian, uint8(1))
  921. buf.Write(testPayload)
  922. return buf.Bytes()
  923. },
  924. },
  925. {
  926. name: "has_empty_payload",
  927. err: nil,
  928. vaa: &VAA{},
  929. expectedVAA: &VAA{
  930. Nonce: uint32(123),
  931. Sequence: uint64(42),
  932. ConsistencyLevel: uint8(1),
  933. EmitterChain: ChainIDBSC,
  934. Timestamp: time.Unix(0, 0),
  935. EmitterAddress: addr,
  936. Payload: []byte{},
  937. },
  938. dataFunc: func() []byte {
  939. buf := new(bytes.Buffer)
  940. MustWrite(buf, binary.BigEndian, uint32(0))
  941. MustWrite(buf, binary.BigEndian, uint32(123))
  942. MustWrite(buf, binary.BigEndian, ChainIDBSC)
  943. buf.Write(addr[:])
  944. MustWrite(buf, binary.BigEndian, uint64(42))
  945. MustWrite(buf, binary.BigEndian, uint8(1))
  946. buf.Write([]byte{})
  947. return buf.Bytes()
  948. },
  949. },
  950. }
  951. for _, testCase := range tests {
  952. t.Run(testCase.name, func(t *testing.T) {
  953. testBytes := testCase.dataFunc()
  954. body, err := UnmarshalBody(testCase.data, bytes.NewReader(testBytes), testCase.vaa)
  955. require.Equal(t, testCase.err, err)
  956. if err == nil {
  957. assert.Equal(t, testCase.expectedVAA, body)
  958. }
  959. })
  960. }
  961. }