structs_test.go 32 KB

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