parse_config_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. package ccq
  2. import (
  3. "encoding/hex"
  4. "strings"
  5. "testing"
  6. "github.com/certusone/wormhole/node/pkg/common"
  7. "github.com/certusone/wormhole/node/pkg/query"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. "github.com/wormhole-foundation/wormhole/sdk/vaa"
  11. "go.uber.org/zap"
  12. "golang.org/x/time/rate"
  13. )
  14. func TestParseConfigFileDoesntExist(t *testing.T) {
  15. _, err := parseConfigFile("missingFile.json", common.MainNet)
  16. require.Error(t, err)
  17. assert.Equal(t, `failed to open permissions file "missingFile.json": open missingFile.json: no such file or directory`, err.Error())
  18. }
  19. func TestParseConfigBadJson(t *testing.T) {
  20. str := `
  21. {
  22. "permissions": [
  23. {
  24. "userName": "Test User",
  25. "apiKey": "my_secret_key",
  26. "allowedCalls": [
  27. {
  28. "ethCall": {
  29. "note:": "Name of WETH on Goerli",
  30. "chain": 2,
  31. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  32. "call": "0x06fdde03"
  33. }
  34. }
  35. ]
  36. },
  37. {
  38. "userName": "Test User",
  39. "apiKey": "my_secret_key_2",
  40. "allowUnsigned": true,
  41. "allowedCalls": [
  42. {
  43. "ethCall": {
  44. "note:": "Name of WETH on Goerli",
  45. "chain": 2,
  46. "contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  47. "call": "0x06fdde03"
  48. }
  49. }
  50. ]
  51. }`
  52. _, err := parseConfig([]byte(str), common.MainNet)
  53. require.Error(t, err)
  54. assert.Equal(t, `failed to unmarshal json: unexpected end of JSON input`, err.Error())
  55. }
  56. func TestParseConfigDuplicateUser(t *testing.T) {
  57. str := `
  58. {
  59. "permissions": [
  60. {
  61. "userName": "Test User",
  62. "apiKey": "my_secret_key",
  63. "allowedCalls": [
  64. {
  65. "ethCall": {
  66. "note:": "Name of WETH on Goerli",
  67. "chain": 2,
  68. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  69. "call": "0x06fdde03"
  70. }
  71. }
  72. ]
  73. },
  74. {
  75. "userName": "Test User",
  76. "apiKey": "my_secret_key_2",
  77. "allowUnsigned": true,
  78. "allowedCalls": [
  79. {
  80. "ethCall": {
  81. "note:": "Name of WETH on Goerli",
  82. "chain": 2,
  83. "contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  84. "call": "0x06fdde03"
  85. }
  86. }
  87. ]
  88. }
  89. ]
  90. }`
  91. _, err := parseConfig([]byte(str), common.MainNet)
  92. require.Error(t, err)
  93. assert.Equal(t, `UserName "Test User" is a duplicate`, err.Error())
  94. }
  95. func TestParseConfigDuplicateApiKey(t *testing.T) {
  96. str := `
  97. {
  98. "permissions": [
  99. {
  100. "userName": "Test User 1",
  101. "apiKey": "my_secret_key",
  102. "allowedCalls": [
  103. {
  104. "ethCall": {
  105. "note:": "Name of WETH on Goerli",
  106. "chain": 2,
  107. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  108. "call": "0x06fdde03"
  109. }
  110. }
  111. ]
  112. },
  113. {
  114. "userName": "Test User 2",
  115. "apiKey": "my_secret_key",
  116. "allowUnsigned": true,
  117. "allowedCalls": [
  118. {
  119. "ethCall": {
  120. "note:": "Name of WETH on Goerli",
  121. "chain": 2,
  122. "contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  123. "call": "0x06fdde03"
  124. }
  125. }
  126. ]
  127. }
  128. ]
  129. }`
  130. _, err := parseConfig([]byte(str), common.MainNet)
  131. require.Error(t, err)
  132. assert.Equal(t, `API key "my_secret_key" is a duplicate`, err.Error())
  133. }
  134. func TestParseConfigUnsupportedCallType(t *testing.T) {
  135. str := `
  136. {
  137. "permissions": [
  138. {
  139. "userName": "Test User",
  140. "apiKey": "my_secret_key",
  141. "allowedCalls": [
  142. {
  143. "badCallType": {
  144. "note:": "Name of WETH on Goerli",
  145. "chain": 2,
  146. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  147. "call": "0x06fdde03"
  148. }
  149. }
  150. ]
  151. }
  152. ]
  153. }`
  154. _, err := parseConfig([]byte(str), common.MainNet)
  155. require.Error(t, err)
  156. assert.Equal(t, `unsupported call type for user "Test User", must be "ethCall", "ethCallByTimestamp", "ethCallWithFinality", "solAccount" or "solPDA"`, err.Error())
  157. }
  158. func TestParseConfigInvalidContractAddress(t *testing.T) {
  159. str := `
  160. {
  161. "permissions": [
  162. {
  163. "userName": "Test User",
  164. "apiKey": "my_secret_key",
  165. "allowedCalls": [
  166. {
  167. "ethCall": {
  168. "note:": "Name of WETH on Goerli",
  169. "chain": 2,
  170. "contractAddress": "HelloWorld",
  171. "call": "0x06fdde"
  172. }
  173. }
  174. ]
  175. }
  176. ]
  177. }`
  178. _, err := parseConfig([]byte(str), common.MainNet)
  179. require.Error(t, err)
  180. assert.Equal(t, `invalid contract address "HelloWorld" for user "Test User"`, err.Error())
  181. }
  182. func TestParseConfigInvalidEthCall(t *testing.T) {
  183. str := `
  184. {
  185. "permissions": [
  186. {
  187. "userName": "Test User",
  188. "apiKey": "my_secret_key",
  189. "allowedCalls": [
  190. {
  191. "ethCall": {
  192. "note:": "Name of WETH on Goerli",
  193. "chain": 2,
  194. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  195. "call": "HelloWorld"
  196. }
  197. }
  198. ]
  199. }
  200. ]
  201. }`
  202. _, err := parseConfig([]byte(str), common.MainNet)
  203. require.Error(t, err)
  204. assert.Equal(t, `invalid eth call "HelloWorld" for user "Test User"`, err.Error())
  205. }
  206. func TestParseConfigInvalidEthCallLength(t *testing.T) {
  207. str := `
  208. {
  209. "permissions": [
  210. {
  211. "userName": "Test User",
  212. "apiKey": "my_secret_key",
  213. "allowedCalls": [
  214. {
  215. "ethCall": {
  216. "note:": "Name of WETH on Goerli",
  217. "chain": 2,
  218. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  219. "call": "0x06fd"
  220. }
  221. }
  222. ]
  223. }
  224. ]
  225. }`
  226. _, err := parseConfig([]byte(str), common.MainNet)
  227. require.Error(t, err)
  228. assert.Equal(t, `eth call "0x06fd" for user "Test User" has an invalid length, must be 4 bytes`, err.Error())
  229. }
  230. func TestParseConfigDuplicateAllowedCallForUser(t *testing.T) {
  231. str := `
  232. {
  233. "permissions": [
  234. {
  235. "userName": "Test User",
  236. "apiKey": "my_secret_key",
  237. "allowedCalls": [
  238. {
  239. "ethCall": {
  240. "note:": "Name of WETH on Goerli",
  241. "chain": 2,
  242. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  243. "call": "0x06fdde03"
  244. }
  245. },
  246. {
  247. "ethCall": {
  248. "note:": "Name of WETH on Goerli",
  249. "chain": 2,
  250. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  251. "call": "0x06fdde03"
  252. }
  253. }
  254. ]
  255. }
  256. ]
  257. }`
  258. _, err := parseConfig([]byte(str), common.MainNet)
  259. require.Error(t, err)
  260. assert.Equal(t, `"ethCall:2:000000000000000000000000b4fbf271143f4fbf7b91a5ded31805e42b2208d6:06fdde03" is a duplicate allowed call for user "Test User"`, err.Error())
  261. }
  262. func TestParseConfigSuccess(t *testing.T) {
  263. str := `
  264. {
  265. "permissions": [
  266. {
  267. "userName": "Test User",
  268. "apiKey": "My_secret_key",
  269. "allowedCalls": [
  270. {
  271. "ethCall": {
  272. "note:": "Name of WETH on Goerli",
  273. "chain": 2,
  274. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  275. "call": "0x06fdde03"
  276. }
  277. },
  278. {
  279. "ethCallByTimestamp": {
  280. "note:": "Name of WETH on Goerli",
  281. "chain": 2,
  282. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d7",
  283. "call": "0x06fdde03"
  284. }
  285. },
  286. {
  287. "ethCallWithFinality": {
  288. "note:": "Decimals of WETH on Devnet",
  289. "chain": 2,
  290. "contractAddress": "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E",
  291. "call": "0x313ce567"
  292. }
  293. },
  294. {
  295. "solAccount": {
  296. "note:": "Example NFT on Devnet",
  297. "chain": 1,
  298. "account": "BVxyYhm498L79r4HMQ9sxZ5bi41DmJmeWZ7SCS7Cyvna"
  299. }
  300. },
  301. {
  302. "solPDA": {
  303. "note:": "Core Bridge on Devnet",
  304. "chain": 1,
  305. "programAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
  306. }
  307. }
  308. ]
  309. }
  310. ]
  311. }`
  312. perms, err := parseConfig([]byte(str), common.MainNet)
  313. require.NoError(t, err)
  314. assert.Equal(t, 1, len(perms))
  315. perm, exists := perms["my_secret_key"]
  316. require.True(t, exists)
  317. assert.Equal(t, 5, len(perm.allowedCalls))
  318. _, exists = perm.allowedCalls["ethCall:2:000000000000000000000000b4fbf271143f4fbf7b91a5ded31805e42b2208d6:06fdde03"]
  319. assert.True(t, exists)
  320. _, exists = perm.allowedCalls["ethCallByTimestamp:2:000000000000000000000000b4fbf271143f4fbf7b91a5ded31805e42b2208d7:06fdde03"]
  321. assert.True(t, exists)
  322. _, exists = perm.allowedCalls["ethCallWithFinality:2:000000000000000000000000ddb64fe46a91d46ee29420539fc25fd07c5fea3e:313ce567"]
  323. assert.True(t, exists)
  324. _, exists = perm.allowedCalls["solAccount:1:BVxyYhm498L79r4HMQ9sxZ5bi41DmJmeWZ7SCS7Cyvna"]
  325. assert.True(t, exists)
  326. _, exists = perm.allowedCalls["solPDA:1:Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"]
  327. assert.True(t, exists)
  328. }
  329. func TestParseConfigAllowAnythingWhenNotSpecified(t *testing.T) {
  330. str := `
  331. {
  332. "permissions": [
  333. {
  334. "userName": "Test User",
  335. "apiKey": "my_secret_key",
  336. "allowedCalls": [
  337. {
  338. "ethCall": {
  339. "note:": "Name of WETH on Goerli",
  340. "chain": 2,
  341. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  342. "call": "0x06fdde03"
  343. }
  344. }
  345. ]
  346. },
  347. {
  348. "userName": "Test User2",
  349. "apiKey": "my_secret_key_2",
  350. "allowUnsigned": true,
  351. "allowAnything": true
  352. }
  353. ]
  354. }`
  355. _, err := parseConfig([]byte(str), common.TestNet)
  356. require.Error(t, err)
  357. assert.Equal(t, `UserName "Test User2" has "allowAnything" specified when the feature is not enabled`, err.Error())
  358. }
  359. func TestParseConfigAllowAnythingWhenNotEnabled(t *testing.T) {
  360. str := `
  361. {
  362. "AllowAnythingSupported": false,
  363. "permissions": [
  364. {
  365. "userName": "Test User",
  366. "apiKey": "my_secret_key",
  367. "allowedCalls": [
  368. {
  369. "ethCall": {
  370. "note:": "Name of WETH on Goerli",
  371. "chain": 2,
  372. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  373. "call": "0x06fdde03"
  374. }
  375. }
  376. ]
  377. },
  378. {
  379. "userName": "Test User2",
  380. "apiKey": "my_secret_key_2",
  381. "allowUnsigned": true,
  382. "allowAnything": true
  383. }
  384. ]
  385. }`
  386. _, err := parseConfig([]byte(str), common.TestNet)
  387. require.Error(t, err)
  388. assert.Equal(t, `UserName "Test User2" has "allowAnything" specified when the feature is not enabled`, err.Error())
  389. }
  390. func TestParseConfigAllowAnythingWithAllowedCallsIsInvalid(t *testing.T) {
  391. str := `
  392. {
  393. "allowAnythingSupported": true,
  394. "permissions": [
  395. {
  396. "userName": "Test User",
  397. "apiKey": "my_secret_key",
  398. "allowedCalls": [
  399. {
  400. "ethCall": {
  401. "note:": "Name of WETH on Goerli",
  402. "chain": 2,
  403. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  404. "call": "0x06fdde03"
  405. }
  406. }
  407. ]
  408. },
  409. {
  410. "userName": "Test User2",
  411. "apiKey": "my_secret_key_2",
  412. "allowUnsigned": true,
  413. "allowAnything": true,
  414. "allowedCalls": [
  415. {
  416. "ethCall": {
  417. "note:": "Name of WETH on Goerli",
  418. "chain": 2,
  419. "contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  420. "call": "0x06fdde03"
  421. }
  422. }
  423. ]
  424. }
  425. ]
  426. }`
  427. _, err := parseConfig([]byte(str), common.TestNet)
  428. require.Error(t, err)
  429. assert.Equal(t, `UserName "Test User2" has "allowedCalls" specified with "allowAnything", which is not allowed`, err.Error())
  430. }
  431. func TestParseConfigAllowAnythingNotAllowedInMainnet(t *testing.T) {
  432. str := `
  433. {
  434. "allowAnythingSupported": true,
  435. "permissions": [
  436. {
  437. "userName": "Test User",
  438. "apiKey": "my_secret_key",
  439. "allowedCalls": [
  440. {
  441. "ethCall": {
  442. "note:": "Name of WETH on Goerli",
  443. "chain": 2,
  444. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  445. "call": "0x06fdde03"
  446. }
  447. }
  448. ]
  449. },
  450. {
  451. "userName": "Test User2",
  452. "apiKey": "my_secret_key_2",
  453. "allowUnsigned": true,
  454. "allowAnything": true
  455. }
  456. ]
  457. }`
  458. _, err := parseConfig([]byte(str), common.MainNet)
  459. require.Equal(t, `the "allowAnythingSupported" flag is not supported in mainnet`, err.Error())
  460. }
  461. func TestParseConfigAllowAnythingSuccess(t *testing.T) {
  462. str := `
  463. {
  464. "allowAnythingSupported": true,
  465. "permissions": [
  466. {
  467. "userName": "Test User",
  468. "apiKey": "my_secret_key",
  469. "allowedCalls": [
  470. {
  471. "ethCall": {
  472. "note:": "Name of WETH on Goerli",
  473. "chain": 2,
  474. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  475. "call": "0x06fdde03"
  476. }
  477. }
  478. ]
  479. },
  480. {
  481. "userName": "Test User2",
  482. "apiKey": "my_secret_key_2",
  483. "allowUnsigned": true,
  484. "allowAnything": true
  485. }
  486. ]
  487. }`
  488. perms, err := parseConfig([]byte(str), common.TestNet)
  489. require.NoError(t, err)
  490. assert.Equal(t, 2, len(perms))
  491. perm, ok := perms["my_secret_key"]
  492. require.True(t, ok)
  493. assert.False(t, perm.allowAnything)
  494. perm, ok = perms["my_secret_key_2"]
  495. require.True(t, ok)
  496. assert.True(t, perm.allowAnything)
  497. }
  498. func TestParseConfigContractWildcard(t *testing.T) {
  499. str := `
  500. {
  501. "permissions": [
  502. {
  503. "userName": "Test User",
  504. "apiKey": "my_secret_key",
  505. "allowedCalls": [
  506. {
  507. "ethCall": {
  508. "note:": "Name of anything on Goerli",
  509. "chain": 2,
  510. "contractAddress": "*",
  511. "call": "0x06fdde03"
  512. }
  513. },
  514. {
  515. "ethCallByTimestamp": {
  516. "note:": "Total supply of WETH on Goerli",
  517. "chain": 2,
  518. "contractAddress": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  519. "call": "0x18160ddd"
  520. }
  521. }
  522. ]
  523. }
  524. ]
  525. }`
  526. perms, err := parseConfig([]byte(str), common.MainNet)
  527. require.NoError(t, err)
  528. assert.Equal(t, 1, len(perms))
  529. permsForUser, ok := perms["my_secret_key"]
  530. require.True(t, ok)
  531. assert.Equal(t, 2, len(permsForUser.allowedCalls))
  532. logger := zap.NewNop()
  533. type testCase struct {
  534. label string
  535. callType string
  536. chainID vaa.ChainID
  537. contractAddress string
  538. data string
  539. errText string // empty string means success
  540. }
  541. var testCases = []testCase{
  542. {
  543. label: "Wild card, success",
  544. callType: "ethCall",
  545. chainID: vaa.ChainIDEthereum,
  546. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  547. data: "0x06fdde03",
  548. errText: "",
  549. },
  550. {
  551. label: "Wild card, success, different address",
  552. callType: "ethCall",
  553. chainID: vaa.ChainIDEthereum,
  554. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d7",
  555. data: "0x06fdde03",
  556. errText: "",
  557. },
  558. {
  559. label: "Wild card, wrong call type",
  560. callType: "ethCallByTimestamp",
  561. chainID: vaa.ChainIDEthereum,
  562. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  563. data: "0x06fdde03",
  564. errText: "not authorized",
  565. },
  566. {
  567. label: "Wild card, wrong chain",
  568. callType: "ethCall",
  569. chainID: vaa.ChainIDBase,
  570. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  571. data: "0x06fdde03",
  572. errText: "not authorized",
  573. },
  574. {
  575. label: "Specific, success",
  576. callType: "ethCallByTimestamp",
  577. chainID: vaa.ChainIDEthereum,
  578. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  579. data: "0x18160ddd",
  580. errText: "",
  581. },
  582. {
  583. label: "Specific, wrong call type",
  584. callType: "ethCall",
  585. chainID: vaa.ChainIDEthereum,
  586. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  587. data: "0x18160ddd",
  588. errText: "not authorized",
  589. },
  590. {
  591. label: "Specific, wrong chain",
  592. callType: "ethCallByTimestamp",
  593. chainID: vaa.ChainIDBase,
  594. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  595. data: "0x18160ddd",
  596. errText: "not authorized",
  597. },
  598. {
  599. label: "Specific, wrong address",
  600. callType: "ethCallByTimestamp",
  601. chainID: vaa.ChainIDEthereum,
  602. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d7",
  603. data: "0x18160ddd",
  604. errText: "not authorized",
  605. },
  606. {
  607. label: "Specific, wrong data",
  608. callType: "ethCallByTimestamp",
  609. chainID: vaa.ChainIDEthereum,
  610. contractAddress: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  611. data: "0x18160dde",
  612. errText: "not authorized",
  613. },
  614. }
  615. for _, tst := range testCases {
  616. t.Run(tst.label, func(t *testing.T) {
  617. status, err := validateCallData(logger, permsForUser, tst.callType, tst.chainID, createCallData(t, tst.contractAddress, tst.data))
  618. if tst.errText == "" {
  619. require.NoError(t, err)
  620. assert.Equal(t, 200, status)
  621. } else {
  622. require.ErrorContains(t, err, tst.errText)
  623. }
  624. })
  625. }
  626. }
  627. func createCallData(t *testing.T, toStr string, dataStr string) []*query.EthCallData {
  628. t.Helper()
  629. to, err := vaa.StringToAddress(strings.TrimPrefix(toStr, "0x"))
  630. require.NoError(t, err)
  631. data, err := hex.DecodeString(strings.TrimPrefix(dataStr, "0x"))
  632. require.NoError(t, err)
  633. return []*query.EthCallData{
  634. {
  635. To: to.Bytes(),
  636. Data: data,
  637. },
  638. }
  639. }
  640. func TestParseConfigWithRateLimiterNoDefaults(t *testing.T) {
  641. str := `
  642. {
  643. "permissions": [
  644. {
  645. "userName": "Test user without rate limits",
  646. "apiKey": "my_secret_key_without_rate_limits",
  647. "allowedCalls": [
  648. {
  649. "ethCall": {
  650. "note:": "Name of WETH on Goerli",
  651. "chain": 2,
  652. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  653. "call": "0x06fdde03"
  654. }
  655. }
  656. ]
  657. },
  658. {
  659. "userName": "Test user with rate limits",
  660. "apiKey": "my_secret_key_with_rate_limits",
  661. "rateLimit": 0.5,
  662. "burstSize": 1,
  663. "allowedCalls": [
  664. {
  665. "ethCall": {
  666. "note:": "Name of WETH on Goerli",
  667. "chain": 2,
  668. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  669. "call": "0x06fdde03"
  670. }
  671. }
  672. ]
  673. }
  674. ]
  675. }`
  676. perms, err := parseConfig([]byte(str), common.MainNet)
  677. require.NoError(t, err)
  678. assert.Equal(t, 2, len(perms))
  679. perm, exists := perms["my_secret_key_without_rate_limits"]
  680. require.True(t, exists)
  681. assert.Nil(t, perm.rateLimiter)
  682. perm, exists = perms["my_secret_key_with_rate_limits"]
  683. require.True(t, exists)
  684. require.NotNil(t, perm.rateLimiter)
  685. assert.Equal(t, rate.Limit(0.5), perm.rateLimiter.Limit())
  686. assert.Equal(t, 1, perm.rateLimiter.Burst())
  687. }
  688. func TestParseConfigWithRateLimiterWithDefaults(t *testing.T) {
  689. str := `
  690. {
  691. "defaultRateLimit": 0.5,
  692. "defaultBurstSize": 1,
  693. "permissions": [
  694. {
  695. "userName": "Test user using default rate limits",
  696. "apiKey": "my_secret_key_using_default_rate_limits",
  697. "allowedCalls": [
  698. {
  699. "ethCall": {
  700. "note:": "Name of WETH on Goerli",
  701. "chain": 2,
  702. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  703. "call": "0x06fdde03"
  704. }
  705. }
  706. ]
  707. },
  708. {
  709. "userName": "Test user overriding default rate limits",
  710. "apiKey": "my_secret_key_overriding_default_rate_limits",
  711. "rateLimit": 1,
  712. "burstSize": 2,
  713. "allowedCalls": [
  714. {
  715. "ethCall": {
  716. "note:": "Name of WETH on Goerli",
  717. "chain": 2,
  718. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  719. "call": "0x06fdde03"
  720. }
  721. }
  722. ]
  723. },
  724. {
  725. "userName": "Test user disabling rate limits",
  726. "apiKey": "my_secret_key_disabling_rate_limits",
  727. "rateLimit": 0,
  728. "allowedCalls": [
  729. {
  730. "ethCall": {
  731. "note:": "Name of WETH on Goerli",
  732. "chain": 2,
  733. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  734. "call": "0x06fdde03"
  735. }
  736. }
  737. ]
  738. }
  739. ]
  740. }`
  741. perms, err := parseConfig([]byte(str), common.MainNet)
  742. require.NoError(t, err)
  743. assert.Equal(t, 3, len(perms))
  744. perm, exists := perms["my_secret_key_using_default_rate_limits"]
  745. require.True(t, exists)
  746. require.NotNil(t, perm.rateLimiter)
  747. assert.Equal(t, rate.Limit(0.5), perm.rateLimiter.Limit())
  748. assert.Equal(t, 1, perm.rateLimiter.Burst())
  749. perm, exists = perms["my_secret_key_overriding_default_rate_limits"]
  750. require.True(t, exists)
  751. require.NotNil(t, perm.rateLimiter)
  752. assert.Equal(t, rate.Limit(1.0), perm.rateLimiter.Limit())
  753. assert.Equal(t, 2, perm.rateLimiter.Burst())
  754. perm, exists = perms["my_secret_key_disabling_rate_limits"]
  755. require.True(t, exists)
  756. require.Nil(t, perm.rateLimiter)
  757. }
  758. func TestParseConfigWithRateLimiterPerUser(t *testing.T) {
  759. str := `
  760. {
  761. "defaultRateLimit": 0.5,
  762. "defaultBurstSize": 1,
  763. "permissions": [
  764. {
  765. "userName": "Test User",
  766. "apiKey": "My_secret_key",
  767. "rateLimit": 1.5,
  768. "burstSize": 3,
  769. "allowedCalls": [
  770. {
  771. "ethCall": {
  772. "note:": "Name of WETH on Goerli",
  773. "chain": 2,
  774. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  775. "call": "0x06fdde03"
  776. }
  777. }
  778. ]
  779. },
  780. {
  781. "userName": "Test User 2",
  782. "apiKey": "My_secret_key_2",
  783. "allowedCalls": [
  784. {
  785. "ethCall": {
  786. "note:": "Name of WETH on Goerli",
  787. "chain": 2,
  788. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  789. "call": "0x06fdde03"
  790. }
  791. }
  792. ]
  793. }
  794. ]
  795. }`
  796. perms, err := parseConfig([]byte(str), common.MainNet)
  797. require.NoError(t, err)
  798. assert.Equal(t, 2, len(perms))
  799. perm, exists := perms["my_secret_key"]
  800. require.True(t, exists)
  801. require.NotNil(t, perm.rateLimiter)
  802. assert.Equal(t, rate.Limit(1.5), perm.rateLimiter.Limit())
  803. assert.Equal(t, 3, perm.rateLimiter.Burst())
  804. perm, exists = perms["my_secret_key_2"]
  805. require.True(t, exists)
  806. require.NotNil(t, perm.rateLimiter)
  807. assert.Equal(t, rate.Limit(0.5), perm.rateLimiter.Limit())
  808. assert.Equal(t, 1, perm.rateLimiter.Burst())
  809. }
  810. func TestParseConfigWithRateLimiterButDefaultBurstSizeNotSet(t *testing.T) {
  811. str := `
  812. {
  813. "defaultRateLimit": 0.5,
  814. "permissions": [
  815. {
  816. "userName": "Test user using default rate limits",
  817. "apiKey": "my_secret_key_using_default_rate_limits",
  818. "allowedCalls": [
  819. {
  820. "ethCall": {
  821. "note:": "Name of WETH on Goerli",
  822. "chain": 2,
  823. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  824. "call": "0x06fdde03"
  825. }
  826. }
  827. ]
  828. }
  829. ]
  830. }`
  831. perms, err := parseConfig([]byte(str), common.MainNet)
  832. require.NoError(t, err)
  833. assert.Equal(t, 1, len(perms))
  834. perm, exists := perms["my_secret_key_using_default_rate_limits"]
  835. require.True(t, exists)
  836. require.NotNil(t, perm.rateLimiter)
  837. assert.Equal(t, rate.Limit(0.5), perm.rateLimiter.Limit())
  838. assert.Equal(t, 1, perm.rateLimiter.Burst())
  839. }
  840. func TestParseConfigWithRateLimiterButDefaultBurstSizeNIsSetToZero(t *testing.T) {
  841. str := `
  842. {
  843. "defaultBurstSize": 0,
  844. "permissions": [
  845. {
  846. "userName": "Test user using default rate limits",
  847. "apiKey": "my_secret_key_using_default_rate_limits",
  848. "allowedCalls": [
  849. {
  850. "ethCall": {
  851. "note:": "Name of WETH on Goerli",
  852. "chain": 2,
  853. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  854. "call": "0x06fdde03"
  855. }
  856. }
  857. ]
  858. }
  859. ]
  860. }`
  861. _, err := parseConfig([]byte(str), common.MainNet)
  862. assert.Equal(t, "the default burst size may not be zero", err.Error())
  863. }
  864. func TestParseConfigWithRateLimiterButPerUserBurstSizeSetToZero(t *testing.T) {
  865. str := `
  866. {
  867. "defaultRateLimit": 0.5,
  868. "defaultBurstSize": 1,
  869. "permissions": [
  870. {
  871. "userName": "Test user overriding default rate limits",
  872. "apiKey": "my_secret_key_overriding_default_rate_limits",
  873. "rateLimit": 1,
  874. "burstSize": 0,
  875. "allowedCalls": [
  876. {
  877. "ethCall": {
  878. "note:": "Name of WETH on Goerli",
  879. "chain": 2,
  880. "contractAddress": "B4FBF271143F4FBf7B91A5ded31805e42b2208d6",
  881. "call": "0x06fdde03"
  882. }
  883. }
  884. ]
  885. }
  886. ]
  887. }`
  888. _, err := parseConfig([]byte(str), common.MainNet)
  889. assert.Equal(t, "if rate limiting is enabled, the burst size may not be zero", err.Error())
  890. }