response.go 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. package query
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/hex"
  6. "fmt"
  7. "math"
  8. "time"
  9. gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
  10. "github.com/ethereum/go-ethereum/common"
  11. "github.com/ethereum/go-ethereum/crypto"
  12. "github.com/wormhole-foundation/wormhole/sdk/vaa"
  13. )
  14. // QueryStatus is the status returned from the watcher to the query handler.
  15. type QueryStatus int
  16. const (
  17. // QuerySuccess means the query was successful and the response should be returned to the requester.
  18. QuerySuccess QueryStatus = 1
  19. // QueryRetryNeeded means the query failed, but a retry may be helpful.
  20. QueryRetryNeeded QueryStatus = 0
  21. // QueryFatalError means the query failed, and there is no point in retrying it.
  22. QueryFatalError QueryStatus = -1
  23. )
  24. // This is the query response returned from the watcher to the query handler.
  25. type PerChainQueryResponseInternal struct {
  26. RequestID string
  27. RequestIdx int
  28. ChainId vaa.ChainID
  29. Status QueryStatus
  30. Response ChainSpecificResponse
  31. }
  32. // CreatePerChainQueryResponseInternal creates a PerChainQueryResponseInternal and returns a pointer to it.
  33. func CreatePerChainQueryResponseInternal(reqId string, reqIdx int, chainId vaa.ChainID, status QueryStatus, response ChainSpecificResponse) *PerChainQueryResponseInternal {
  34. return &PerChainQueryResponseInternal{
  35. RequestID: reqId,
  36. RequestIdx: reqIdx,
  37. ChainId: chainId,
  38. Status: status,
  39. Response: response,
  40. }
  41. }
  42. var queryResponsePrefix = []byte("query_response_0000000000000000000|")
  43. // QueryResponsePublication is the response to a QueryRequest.
  44. type QueryResponsePublication struct {
  45. Request *gossipv1.SignedQueryRequest
  46. PerChainResponses []*PerChainQueryResponse
  47. }
  48. // PerChainQueryResponse represents a query response for a single chain.
  49. type PerChainQueryResponse struct {
  50. // ChainId indicates which chain this query was destine for.
  51. ChainId vaa.ChainID
  52. // Response is the chain specific query data.
  53. Response ChainSpecificResponse
  54. }
  55. // ChainSpecificResponse is the interface that must be implemented by a chain specific response.
  56. type ChainSpecificResponse interface {
  57. Type() ChainSpecificQueryType
  58. Marshal() ([]byte, error)
  59. Unmarshal(data []byte) error
  60. UnmarshalFromReader(reader *bytes.Reader) error
  61. Validate() error
  62. }
  63. // EthCallQueryResponse implements ChainSpecificResponse for an EVM eth_call query response.
  64. type EthCallQueryResponse struct {
  65. BlockNumber uint64
  66. Hash common.Hash
  67. Time time.Time
  68. // Results is the array of responses matching CallData in EthCallQueryRequest
  69. Results [][]byte
  70. }
  71. // EthCallByTimestampQueryResponse implements ChainSpecificResponse for an EVM eth_call_by_timestamp query response.
  72. type EthCallByTimestampQueryResponse struct {
  73. TargetBlockNumber uint64
  74. TargetBlockHash common.Hash
  75. TargetBlockTime time.Time
  76. FollowingBlockNumber uint64
  77. FollowingBlockHash common.Hash
  78. FollowingBlockTime time.Time
  79. // Results is the array of responses matching CallData in EthCallByTimestampQueryRequest
  80. Results [][]byte
  81. }
  82. // EthCallWithFinalityQueryResponse implements ChainSpecificResponse for an EVM eth_call_with_finality query response.
  83. type EthCallWithFinalityQueryResponse struct {
  84. BlockNumber uint64
  85. Hash common.Hash
  86. Time time.Time
  87. // Results is the array of responses matching CallData in EthCallQueryRequest
  88. Results [][]byte
  89. }
  90. // SolanaAccountQueryResponse implements ChainSpecificResponse for a Solana sol_account query response.
  91. type SolanaAccountQueryResponse struct {
  92. // SlotNumber is the slot number returned by the sol_account query
  93. SlotNumber uint64
  94. // BlockTime is the block time associated with the slot.
  95. BlockTime time.Time
  96. // BlockHash is the block hash associated with the slot.
  97. BlockHash [SolanaPublicKeyLength]byte
  98. Results []SolanaAccountResult
  99. }
  100. type SolanaAccountResult struct {
  101. // Lamports is the number of lamports assigned to the account.
  102. Lamports uint64
  103. // RentEpoch is the epoch at which this account will next owe rent.
  104. RentEpoch uint64
  105. // Executable is a boolean indicating if the account contains a program (and is strictly read-only).
  106. Executable bool
  107. // Owner is the public key of the owner of the account.
  108. Owner [SolanaPublicKeyLength]byte
  109. // Data is the data returned by the sol_account query.
  110. Data []byte
  111. }
  112. // SolanaPdaQueryResponse implements ChainSpecificResponse for a Solana sol_pda query response.
  113. type SolanaPdaQueryResponse struct {
  114. // SlotNumber is the slot number returned by the sol_pda query
  115. SlotNumber uint64
  116. // BlockTime is the block time associated with the slot.
  117. BlockTime time.Time
  118. // BlockHash is the block hash associated with the slot.
  119. BlockHash [SolanaPublicKeyLength]byte
  120. Results []SolanaPdaResult
  121. }
  122. type SolanaPdaResult struct {
  123. // Account is the public key of the account derived from the PDA.
  124. Account [SolanaPublicKeyLength]byte
  125. // Bump is the bump value returned by the solana derivation function.
  126. Bump uint8
  127. // Lamports is the number of lamports assigned to the account.
  128. Lamports uint64
  129. // RentEpoch is the epoch at which this account will next owe rent.
  130. RentEpoch uint64
  131. // Executable is a boolean indicating if the account contains a program (and is strictly read-only).
  132. Executable bool
  133. // Owner is the public key of the owner of the account.
  134. Owner [SolanaPublicKeyLength]byte
  135. // Data is the data returned by the sol_pda query.
  136. Data []byte
  137. }
  138. //
  139. // Implementation of QueryResponsePublication.
  140. //
  141. // Marshal serializes the binary representation of a query response.
  142. // This method calls Validate() and relies on it to range checks lengths, etc.
  143. func (msg *QueryResponsePublication) Marshal() ([]byte, error) {
  144. if err := msg.Validate(); err != nil {
  145. return nil, err
  146. }
  147. buf := new(bytes.Buffer)
  148. vaa.MustWrite(buf, binary.BigEndian, uint8(1)) // version
  149. // Source
  150. // TODO: support writing off-chain and on-chain requests
  151. // Here, unset represents an off-chain request
  152. vaa.MustWrite(buf, binary.BigEndian, vaa.ChainIDUnset)
  153. buf.Write(msg.Request.Signature[:])
  154. // Write the length of the request to facilitate on-chain parsing.
  155. if len(msg.Request.QueryRequest) > math.MaxUint32 {
  156. return nil, fmt.Errorf("request too long")
  157. }
  158. vaa.MustWrite(buf, binary.BigEndian, uint32(len(msg.Request.QueryRequest))) // #nosec G115 -- This is validated above
  159. buf.Write(msg.Request.QueryRequest)
  160. // Per chain responses
  161. vaa.MustWrite(buf, binary.BigEndian, uint8(len(msg.PerChainResponses))) // #nosec G115 -- This is validated in `Validate`
  162. for idx := range msg.PerChainResponses {
  163. pcrBuf, err := msg.PerChainResponses[idx].Marshal()
  164. if err != nil {
  165. return nil, fmt.Errorf("failed to marshal per chain response: %w", err)
  166. }
  167. buf.Write(pcrBuf)
  168. }
  169. return buf.Bytes(), nil
  170. }
  171. // Unmarshal deserializes the binary representation of a query response
  172. func (msg *QueryResponsePublication) Unmarshal(data []byte) error {
  173. reader := bytes.NewReader(data[:])
  174. var version uint8
  175. if err := binary.Read(reader, binary.BigEndian, &version); err != nil {
  176. return fmt.Errorf("failed to read message version: %w", err)
  177. }
  178. if version != 1 {
  179. return fmt.Errorf("unsupported message version: %d", version)
  180. }
  181. // Request
  182. requestChain := vaa.ChainID(0)
  183. if err := binary.Read(reader, binary.BigEndian, &requestChain); err != nil {
  184. return fmt.Errorf("failed to read request chain: %w", err)
  185. }
  186. if requestChain != vaa.ChainIDUnset {
  187. // TODO: support reading off-chain and on-chain requests
  188. return fmt.Errorf("unsupported request chain: %d", requestChain)
  189. }
  190. signedQueryRequest := &gossipv1.SignedQueryRequest{}
  191. signature := [65]byte{}
  192. if n, err := reader.Read(signature[:]); err != nil || n != 65 {
  193. return fmt.Errorf("failed to read signature [%d]: %w", n, err)
  194. }
  195. signedQueryRequest.Signature = signature[:]
  196. // Read the serialized request.
  197. queryRequestLen := uint32(0)
  198. if err := binary.Read(reader, binary.BigEndian, &queryRequestLen); err != nil {
  199. return fmt.Errorf("failed to read length of query request: %w", err)
  200. }
  201. queryRequestBytes := make([]byte, queryRequestLen)
  202. if n, err := reader.Read(queryRequestBytes[:]); err != nil || n != int(queryRequestLen) {
  203. return fmt.Errorf("failed to read query request [%d]: %w", n, err)
  204. }
  205. queryRequest := QueryRequest{}
  206. queryRequestReader := bytes.NewReader(queryRequestBytes[:])
  207. err := queryRequest.UnmarshalFromReader(queryRequestReader)
  208. if err != nil {
  209. return fmt.Errorf("failed to unmarshal query request: %w", err)
  210. }
  211. queryRequestBytes, err = queryRequest.Marshal()
  212. if err != nil {
  213. return err
  214. }
  215. signedQueryRequest.QueryRequest = queryRequestBytes
  216. msg.Request = signedQueryRequest
  217. // Responses
  218. numPerChainResponses := uint8(0)
  219. if err := binary.Read(reader, binary.BigEndian, &numPerChainResponses); err != nil {
  220. return fmt.Errorf("failed to read number of per chain responses: %w", err)
  221. }
  222. for count := 0; count < int(numPerChainResponses); count++ {
  223. var pcr PerChainQueryResponse
  224. err := pcr.UnmarshalFromReader(reader)
  225. if err != nil {
  226. return fmt.Errorf("failed to unmarshal per chain response: %w", err)
  227. }
  228. msg.PerChainResponses = append(msg.PerChainResponses, &pcr)
  229. }
  230. if reader.Len() != 0 {
  231. return fmt.Errorf("excess bytes in unmarshal")
  232. }
  233. if err := msg.Validate(); err != nil {
  234. return fmt.Errorf("unmarshaled response failed validation: %w", err)
  235. }
  236. return nil
  237. }
  238. // Validate does basic validation on a received query request.
  239. func (msg *QueryResponsePublication) Validate() error {
  240. // Unmarshal and validate the contained query request.
  241. var queryRequest QueryRequest
  242. err := queryRequest.Unmarshal(msg.Request.QueryRequest)
  243. if err != nil {
  244. return fmt.Errorf("failed to unmarshal query request: %w", err)
  245. }
  246. if err := queryRequest.Validate(); err != nil {
  247. return fmt.Errorf("query request is invalid: %w", err)
  248. }
  249. if len(msg.PerChainResponses) <= 0 {
  250. return fmt.Errorf("response does not contain any per chain responses")
  251. }
  252. if len(msg.PerChainResponses) > math.MaxUint8 {
  253. return fmt.Errorf("too many per chain responses")
  254. }
  255. if len(msg.PerChainResponses) != len(queryRequest.PerChainQueries) {
  256. return fmt.Errorf("number of responses does not match number of queries")
  257. }
  258. for idx, pcr := range msg.PerChainResponses {
  259. if err := pcr.Validate(); err != nil {
  260. return fmt.Errorf("failed to validate per chain query %d: %w", idx, err)
  261. }
  262. if pcr.Response.Type() != queryRequest.PerChainQueries[idx].Query.Type() {
  263. return fmt.Errorf("type of response %d does not match the query", idx)
  264. }
  265. }
  266. return nil
  267. }
  268. // Equal checks for equality on two query response publications.
  269. func (left *QueryResponsePublication) Equal(right *QueryResponsePublication) bool {
  270. if !bytes.Equal(left.Request.QueryRequest, right.Request.QueryRequest) || !bytes.Equal(left.Request.Signature, right.Request.Signature) {
  271. return false
  272. }
  273. if len(left.PerChainResponses) != len(right.PerChainResponses) {
  274. return false
  275. }
  276. for idx := range left.PerChainResponses {
  277. if !left.PerChainResponses[idx].Equal(right.PerChainResponses[idx]) {
  278. return false
  279. }
  280. }
  281. return true
  282. }
  283. func (resp *QueryResponsePublication) Signature() string {
  284. if resp == nil || resp.Request == nil {
  285. return "nil"
  286. }
  287. return hex.EncodeToString(resp.Request.Signature)
  288. }
  289. // Similar to sdk/vaa/structs.go,
  290. // In order to save space in the solana signature verification instruction, we hash twice so we only need to pass in
  291. // the first hash (32 bytes) vs the full body data.
  292. func (msg *QueryResponsePublication) SigningDigest() (common.Hash, error) {
  293. msgBytes, err := msg.Marshal()
  294. if err != nil {
  295. return common.Hash{}, err
  296. }
  297. return GetQueryResponseDigestFromBytes(msgBytes), nil
  298. }
  299. // GetQueryResponseDigestFromBytes computes the digest bytes for a query response byte array.
  300. func GetQueryResponseDigestFromBytes(b []byte) common.Hash {
  301. return crypto.Keccak256Hash(append(queryResponsePrefix, crypto.Keccak256Hash(b).Bytes()...))
  302. }
  303. //
  304. // Implementation of PerChainQueryResponse.
  305. //
  306. // Marshal marshalls a per chain query response.
  307. func (perChainResponse *PerChainQueryResponse) Marshal() ([]byte, error) {
  308. if err := perChainResponse.Validate(); err != nil {
  309. return nil, err
  310. }
  311. buf := new(bytes.Buffer)
  312. vaa.MustWrite(buf, binary.BigEndian, perChainResponse.ChainId)
  313. vaa.MustWrite(buf, binary.BigEndian, perChainResponse.Response.Type())
  314. respBuf, err := perChainResponse.Response.Marshal()
  315. if err != nil {
  316. return nil, err
  317. }
  318. // Write the length of the response to facilitate on-chain parsing.
  319. if len(respBuf) > math.MaxUint32 {
  320. return nil, fmt.Errorf("response is too long")
  321. }
  322. vaa.MustWrite(buf, binary.BigEndian, uint32(len(respBuf))) // #nosec G115 -- This is validated above
  323. buf.Write(respBuf)
  324. return buf.Bytes(), nil
  325. }
  326. // Unmarshal deserializes the binary representation of a per chain query response from a byte array
  327. func (perChainResponse *PerChainQueryResponse) Unmarshal(data []byte) error {
  328. reader := bytes.NewReader(data[:])
  329. return perChainResponse.UnmarshalFromReader(reader)
  330. }
  331. // UnmarshalFromReader deserializes the binary representation of a per chain query response from an existing reader
  332. func (perChainResponse *PerChainQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  333. if err := binary.Read(reader, binary.BigEndian, &perChainResponse.ChainId); err != nil {
  334. return fmt.Errorf("failed to read response chain: %w", err)
  335. }
  336. qt := uint8(0)
  337. if err := binary.Read(reader, binary.BigEndian, &qt); err != nil {
  338. return fmt.Errorf("failed to read response type: %w", err)
  339. }
  340. queryType := ChainSpecificQueryType(qt)
  341. if err := ValidatePerChainQueryRequestType(queryType); err != nil {
  342. return err
  343. }
  344. // Skip the response length.
  345. var respLength uint32
  346. if err := binary.Read(reader, binary.BigEndian, &respLength); err != nil {
  347. return fmt.Errorf("failed to read response length: %w", err)
  348. }
  349. switch queryType {
  350. case EthCallQueryRequestType:
  351. r := EthCallQueryResponse{}
  352. if err := r.UnmarshalFromReader(reader); err != nil {
  353. return fmt.Errorf("failed to unmarshal eth call response: %w", err)
  354. }
  355. perChainResponse.Response = &r
  356. case EthCallByTimestampQueryRequestType:
  357. r := EthCallByTimestampQueryResponse{}
  358. if err := r.UnmarshalFromReader(reader); err != nil {
  359. return fmt.Errorf("failed to unmarshal eth call by timestamp response: %w", err)
  360. }
  361. perChainResponse.Response = &r
  362. case EthCallWithFinalityQueryRequestType:
  363. r := EthCallWithFinalityQueryResponse{}
  364. if err := r.UnmarshalFromReader(reader); err != nil {
  365. return fmt.Errorf("failed to unmarshal eth call with finality response: %w", err)
  366. }
  367. perChainResponse.Response = &r
  368. case SolanaAccountQueryRequestType:
  369. r := SolanaAccountQueryResponse{}
  370. if err := r.UnmarshalFromReader(reader); err != nil {
  371. return fmt.Errorf("failed to unmarshal sol_account response: %w", err)
  372. }
  373. perChainResponse.Response = &r
  374. case SolanaPdaQueryRequestType:
  375. r := SolanaPdaQueryResponse{}
  376. if err := r.UnmarshalFromReader(reader); err != nil {
  377. return fmt.Errorf("failed to unmarshal sol_account response: %w", err)
  378. }
  379. perChainResponse.Response = &r
  380. default:
  381. return fmt.Errorf("unsupported query type: %d", queryType)
  382. }
  383. return nil
  384. }
  385. // ValidatePerChainResponse performs basic validation on a per chain query response.
  386. func (perChainResponse *PerChainQueryResponse) Validate() error {
  387. str := perChainResponse.ChainId.String()
  388. if _, err := vaa.ChainIDFromString(str); err != nil {
  389. return fmt.Errorf("invalid chainID: %d", uint16(perChainResponse.ChainId))
  390. }
  391. if perChainResponse.Response == nil {
  392. return fmt.Errorf("response is nil")
  393. }
  394. if err := ValidatePerChainQueryRequestType(perChainResponse.Response.Type()); err != nil {
  395. return err
  396. }
  397. if err := perChainResponse.Response.Validate(); err != nil {
  398. return fmt.Errorf("chain specific response is invalid: %w", err)
  399. }
  400. return nil
  401. }
  402. // Equal checks for equality on two per chain query responses.
  403. func (left *PerChainQueryResponse) Equal(right *PerChainQueryResponse) bool {
  404. if left.ChainId != right.ChainId {
  405. return false
  406. }
  407. if left.Response == nil && right.Response == nil {
  408. return true
  409. }
  410. if left.Response == nil || right.Response == nil {
  411. return false
  412. }
  413. if left.Response.Type() != right.Response.Type() {
  414. return false
  415. }
  416. switch leftResp := left.Response.(type) {
  417. case *EthCallQueryResponse:
  418. switch rightResp := right.Response.(type) {
  419. case *EthCallQueryResponse:
  420. return leftResp.Equal(rightResp)
  421. default:
  422. panic("unsupported query type on right") // We checked this above!
  423. }
  424. case *EthCallByTimestampQueryResponse:
  425. switch rightResp := right.Response.(type) {
  426. case *EthCallByTimestampQueryResponse:
  427. return leftResp.Equal(rightResp)
  428. default:
  429. panic("unsupported query type on right") // We checked this above!
  430. }
  431. case *EthCallWithFinalityQueryResponse:
  432. switch rightResp := right.Response.(type) {
  433. case *EthCallWithFinalityQueryResponse:
  434. return leftResp.Equal(rightResp)
  435. default:
  436. panic("unsupported query type on right") // We checked this above!
  437. }
  438. case *SolanaAccountQueryResponse:
  439. switch rightResp := right.Response.(type) {
  440. case *SolanaAccountQueryResponse:
  441. return leftResp.Equal(rightResp)
  442. default:
  443. panic("unsupported query type on right") // We checked this above!
  444. }
  445. case *SolanaPdaQueryResponse:
  446. switch rightResp := right.Response.(type) {
  447. case *SolanaPdaQueryResponse:
  448. return leftResp.Equal(rightResp)
  449. default:
  450. panic("unsupported query type on right") // We checked this above!
  451. }
  452. default:
  453. panic("unsupported query type on left") // We checked this above!
  454. }
  455. }
  456. //
  457. // Implementation of EthCallQueryResponse, which implements the ChainSpecificResponse for an EVM eth_call query response.
  458. //
  459. func (e *EthCallQueryResponse) Type() ChainSpecificQueryType {
  460. return EthCallQueryRequestType
  461. }
  462. // Marshal serializes the binary representation of an EVM eth_call response.
  463. // This method calls Validate() and relies on it to range checks lengths, etc.
  464. func (ecr *EthCallQueryResponse) Marshal() ([]byte, error) {
  465. if err := ecr.Validate(); err != nil {
  466. return nil, err
  467. }
  468. buf := new(bytes.Buffer)
  469. vaa.MustWrite(buf, binary.BigEndian, ecr.BlockNumber)
  470. buf.Write(ecr.Hash[:])
  471. vaa.MustWrite(buf, binary.BigEndian, ecr.Time.UnixMicro())
  472. vaa.MustWrite(buf, binary.BigEndian, uint8(len(ecr.Results))) // #nosec G115 -- This is validated in `Validate`
  473. for idx := range ecr.Results {
  474. vaa.MustWrite(buf, binary.BigEndian, uint32(len(ecr.Results[idx]))) // #nosec G115 -- This is validated in `Validate`
  475. buf.Write(ecr.Results[idx])
  476. }
  477. return buf.Bytes(), nil
  478. }
  479. // Unmarshal deserializes an EVM eth_call response from a byte array
  480. func (ecr *EthCallQueryResponse) Unmarshal(data []byte) error {
  481. reader := bytes.NewReader(data[:])
  482. return ecr.UnmarshalFromReader(reader)
  483. }
  484. // UnmarshalFromReader deserializes an EVM eth_call response from a byte array
  485. func (ecr *EthCallQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  486. if err := binary.Read(reader, binary.BigEndian, &ecr.BlockNumber); err != nil {
  487. return fmt.Errorf("failed to read response number: %w", err)
  488. }
  489. responseHash := common.Hash{}
  490. if n, err := reader.Read(responseHash[:]); err != nil || n != 32 {
  491. return fmt.Errorf("failed to read response hash [%d]: %w", n, err)
  492. }
  493. ecr.Hash = responseHash
  494. unixMicros := int64(0)
  495. if err := binary.Read(reader, binary.BigEndian, &unixMicros); err != nil {
  496. return fmt.Errorf("failed to read response timestamp: %w", err)
  497. }
  498. ecr.Time = time.UnixMicro(unixMicros)
  499. numResults := uint8(0)
  500. if err := binary.Read(reader, binary.BigEndian, &numResults); err != nil {
  501. return fmt.Errorf("failed to read number of results: %w", err)
  502. }
  503. for count := 0; count < int(numResults); count++ {
  504. resultLen := uint32(0)
  505. if err := binary.Read(reader, binary.BigEndian, &resultLen); err != nil {
  506. return fmt.Errorf("failed to read result len: %w", err)
  507. }
  508. result := make([]byte, resultLen)
  509. if n, err := reader.Read(result[:]); err != nil || n != int(resultLen) {
  510. return fmt.Errorf("failed to read result [%d]: %w", n, err)
  511. }
  512. ecr.Results = append(ecr.Results, result)
  513. }
  514. return nil
  515. }
  516. // Validate does basic validation on an EVM eth_call response.
  517. func (ecr *EthCallQueryResponse) Validate() error {
  518. // Not checking for BlockNumber == 0, because maybe that could happen??
  519. if len(ecr.Hash) != 32 {
  520. return fmt.Errorf("invalid length for block hash")
  521. }
  522. if len(ecr.Results) <= 0 {
  523. return fmt.Errorf("does not contain any results")
  524. }
  525. if len(ecr.Results) > math.MaxUint8 {
  526. return fmt.Errorf("too many results")
  527. }
  528. for _, result := range ecr.Results {
  529. if len(result) > math.MaxUint32 {
  530. return fmt.Errorf("result too long")
  531. }
  532. }
  533. return nil
  534. }
  535. // Equal verifies that two EVM eth_call responses are equal.
  536. func (left *EthCallQueryResponse) Equal(right *EthCallQueryResponse) bool {
  537. if left.BlockNumber != right.BlockNumber {
  538. return false
  539. }
  540. if !bytes.Equal(left.Hash.Bytes(), right.Hash.Bytes()) {
  541. return false
  542. }
  543. if left.Time != right.Time {
  544. return false
  545. }
  546. if len(left.Results) != len(right.Results) {
  547. return false
  548. }
  549. for idx := range left.Results {
  550. if !bytes.Equal(left.Results[idx], right.Results[idx]) {
  551. return false
  552. }
  553. }
  554. return true
  555. }
  556. //
  557. // Implementation of EthCallByTimestampQueryResponse, which implements the ChainSpecificResponse for an EVM eth_call_by_timestamp query response.
  558. //
  559. func (e *EthCallByTimestampQueryResponse) Type() ChainSpecificQueryType {
  560. return EthCallByTimestampQueryRequestType
  561. }
  562. // Marshal serializes the binary representation of an EVM eth_call_by_timestamp response.
  563. // This method calls Validate() and relies on it to range checks lengths, etc.
  564. func (ecr *EthCallByTimestampQueryResponse) Marshal() ([]byte, error) {
  565. if err := ecr.Validate(); err != nil {
  566. return nil, err
  567. }
  568. buf := new(bytes.Buffer)
  569. vaa.MustWrite(buf, binary.BigEndian, ecr.TargetBlockNumber)
  570. buf.Write(ecr.TargetBlockHash[:])
  571. vaa.MustWrite(buf, binary.BigEndian, ecr.TargetBlockTime.UnixMicro())
  572. vaa.MustWrite(buf, binary.BigEndian, ecr.FollowingBlockNumber)
  573. buf.Write(ecr.FollowingBlockHash[:])
  574. vaa.MustWrite(buf, binary.BigEndian, ecr.FollowingBlockTime.UnixMicro())
  575. vaa.MustWrite(buf, binary.BigEndian, uint8(len(ecr.Results))) // #nosec G115 -- This is validated in `Validate`
  576. for idx := range ecr.Results {
  577. vaa.MustWrite(buf, binary.BigEndian, uint32(len(ecr.Results[idx]))) // #nosec G115 -- This is validated in `Validate`
  578. buf.Write(ecr.Results[idx])
  579. }
  580. return buf.Bytes(), nil
  581. }
  582. // Unmarshal deserializes an EVM eth_call_by_timestamp response from a byte array
  583. func (ecr *EthCallByTimestampQueryResponse) Unmarshal(data []byte) error {
  584. reader := bytes.NewReader(data[:])
  585. return ecr.UnmarshalFromReader(reader)
  586. }
  587. // UnmarshalFromReader deserializes an EVM eth_call_by_timestamp response from a byte array
  588. func (ecr *EthCallByTimestampQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  589. if err := binary.Read(reader, binary.BigEndian, &ecr.TargetBlockNumber); err != nil {
  590. return fmt.Errorf("failed to read response target block number: %w", err)
  591. }
  592. responseHash := common.Hash{}
  593. if n, err := reader.Read(responseHash[:]); err != nil || n != 32 {
  594. return fmt.Errorf("failed to read response target block hash [%d]: %w", n, err)
  595. }
  596. ecr.TargetBlockHash = responseHash
  597. unixMicros := int64(0)
  598. if err := binary.Read(reader, binary.BigEndian, &unixMicros); err != nil {
  599. return fmt.Errorf("failed to read response target block timestamp: %w", err)
  600. }
  601. ecr.TargetBlockTime = time.UnixMicro(unixMicros)
  602. if err := binary.Read(reader, binary.BigEndian, &ecr.FollowingBlockNumber); err != nil {
  603. return fmt.Errorf("failed to read response following block number: %w", err)
  604. }
  605. responseHash = common.Hash{}
  606. if n, err := reader.Read(responseHash[:]); err != nil || n != 32 {
  607. return fmt.Errorf("failed to read response following block hash [%d]: %w", n, err)
  608. }
  609. ecr.FollowingBlockHash = responseHash
  610. unixMicros = int64(0)
  611. if err := binary.Read(reader, binary.BigEndian, &unixMicros); err != nil {
  612. return fmt.Errorf("failed to read response following block timestamp: %w", err)
  613. }
  614. ecr.FollowingBlockTime = time.UnixMicro(unixMicros)
  615. numResults := uint8(0)
  616. if err := binary.Read(reader, binary.BigEndian, &numResults); err != nil {
  617. return fmt.Errorf("failed to read number of results: %w", err)
  618. }
  619. for count := 0; count < int(numResults); count++ {
  620. resultLen := uint32(0)
  621. if err := binary.Read(reader, binary.BigEndian, &resultLen); err != nil {
  622. return fmt.Errorf("failed to read result len: %w", err)
  623. }
  624. result := make([]byte, resultLen)
  625. if n, err := reader.Read(result[:]); err != nil || n != int(resultLen) {
  626. return fmt.Errorf("failed to read result [%d]: %w", n, err)
  627. }
  628. ecr.Results = append(ecr.Results, result)
  629. }
  630. return nil
  631. }
  632. // Validate does basic validation on an EVM eth_call_by_timestamp response.
  633. func (ecr *EthCallByTimestampQueryResponse) Validate() error {
  634. // Not checking for block numbers == 0, because maybe that could happen??
  635. if len(ecr.TargetBlockHash) != 32 {
  636. return fmt.Errorf("invalid length for target block hash")
  637. }
  638. if len(ecr.FollowingBlockHash) != 32 {
  639. return fmt.Errorf("invalid length for following block hash")
  640. }
  641. if len(ecr.Results) <= 0 {
  642. return fmt.Errorf("does not contain any results")
  643. }
  644. if len(ecr.Results) > math.MaxUint8 {
  645. return fmt.Errorf("too many results")
  646. }
  647. for _, result := range ecr.Results {
  648. if len(result) > math.MaxUint32 {
  649. return fmt.Errorf("result too long")
  650. }
  651. }
  652. return nil
  653. }
  654. // Equal verifies that two EVM eth_call_by_timestamp responses are equal.
  655. func (left *EthCallByTimestampQueryResponse) Equal(right *EthCallByTimestampQueryResponse) bool {
  656. if left.TargetBlockNumber != right.TargetBlockNumber {
  657. return false
  658. }
  659. if !bytes.Equal(left.TargetBlockHash.Bytes(), right.TargetBlockHash.Bytes()) {
  660. return false
  661. }
  662. if left.TargetBlockTime != right.TargetBlockTime {
  663. return false
  664. }
  665. if left.FollowingBlockNumber != right.FollowingBlockNumber {
  666. return false
  667. }
  668. if !bytes.Equal(left.FollowingBlockHash.Bytes(), right.FollowingBlockHash.Bytes()) {
  669. return false
  670. }
  671. if left.FollowingBlockTime != right.FollowingBlockTime {
  672. return false
  673. }
  674. if len(left.Results) != len(right.Results) {
  675. return false
  676. }
  677. for idx := range left.Results {
  678. if !bytes.Equal(left.Results[idx], right.Results[idx]) {
  679. return false
  680. }
  681. }
  682. return true
  683. }
  684. //
  685. // Implementation of EthCallWithFinalityQueryResponse, which implements the ChainSpecificResponse for an EVM eth_call_with_finality query response.
  686. //
  687. func (e *EthCallWithFinalityQueryResponse) Type() ChainSpecificQueryType {
  688. return EthCallWithFinalityQueryRequestType
  689. }
  690. // Marshal serializes the binary representation of an EVM eth_call_with_finality response.
  691. // This method calls Validate() and relies on it to range checks lengths, etc.
  692. func (ecr *EthCallWithFinalityQueryResponse) Marshal() ([]byte, error) {
  693. if err := ecr.Validate(); err != nil {
  694. return nil, err
  695. }
  696. buf := new(bytes.Buffer)
  697. vaa.MustWrite(buf, binary.BigEndian, ecr.BlockNumber)
  698. buf.Write(ecr.Hash[:])
  699. vaa.MustWrite(buf, binary.BigEndian, ecr.Time.UnixMicro())
  700. vaa.MustWrite(buf, binary.BigEndian, uint8(len(ecr.Results))) // #nosec G115 -- This is validated in `Validate`
  701. for idx := range ecr.Results {
  702. vaa.MustWrite(buf, binary.BigEndian, uint32(len(ecr.Results[idx]))) // #nosec G115 -- This is validated in `Validate`
  703. buf.Write(ecr.Results[idx])
  704. }
  705. return buf.Bytes(), nil
  706. }
  707. // Unmarshal deserializes an EVM eth_call_with_finality response from a byte array
  708. func (ecr *EthCallWithFinalityQueryResponse) Unmarshal(data []byte) error {
  709. reader := bytes.NewReader(data[:])
  710. return ecr.UnmarshalFromReader(reader)
  711. }
  712. // UnmarshalFromReader deserializes an EVM eth_call_with_finality response from a byte array
  713. func (ecr *EthCallWithFinalityQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  714. if err := binary.Read(reader, binary.BigEndian, &ecr.BlockNumber); err != nil {
  715. return fmt.Errorf("failed to read response number: %w", err)
  716. }
  717. responseHash := common.Hash{}
  718. if n, err := reader.Read(responseHash[:]); err != nil || n != 32 {
  719. return fmt.Errorf("failed to read response hash [%d]: %w", n, err)
  720. }
  721. ecr.Hash = responseHash
  722. unixMicros := int64(0)
  723. if err := binary.Read(reader, binary.BigEndian, &unixMicros); err != nil {
  724. return fmt.Errorf("failed to read response timestamp: %w", err)
  725. }
  726. ecr.Time = time.UnixMicro(unixMicros)
  727. numResults := uint8(0)
  728. if err := binary.Read(reader, binary.BigEndian, &numResults); err != nil {
  729. return fmt.Errorf("failed to read number of results: %w", err)
  730. }
  731. for count := 0; count < int(numResults); count++ {
  732. resultLen := uint32(0)
  733. if err := binary.Read(reader, binary.BigEndian, &resultLen); err != nil {
  734. return fmt.Errorf("failed to read result len: %w", err)
  735. }
  736. result := make([]byte, resultLen)
  737. if n, err := reader.Read(result[:]); err != nil || n != int(resultLen) {
  738. return fmt.Errorf("failed to read result [%d]: %w", n, err)
  739. }
  740. ecr.Results = append(ecr.Results, result)
  741. }
  742. return nil
  743. }
  744. // Validate does basic validation on an EVM eth_call_with_finality response.
  745. func (ecr *EthCallWithFinalityQueryResponse) Validate() error {
  746. // Not checking for BlockNumber == 0, because maybe that could happen??
  747. if len(ecr.Hash) != 32 {
  748. return fmt.Errorf("invalid length for block hash")
  749. }
  750. if len(ecr.Results) <= 0 {
  751. return fmt.Errorf("does not contain any results")
  752. }
  753. if len(ecr.Results) > math.MaxUint8 {
  754. return fmt.Errorf("too many results")
  755. }
  756. for _, result := range ecr.Results {
  757. if len(result) > math.MaxUint32 {
  758. return fmt.Errorf("result too long")
  759. }
  760. }
  761. return nil
  762. }
  763. // Equal verifies that two EVM eth_call_with_finality responses are equal.
  764. func (left *EthCallWithFinalityQueryResponse) Equal(right *EthCallWithFinalityQueryResponse) bool {
  765. if left.BlockNumber != right.BlockNumber {
  766. return false
  767. }
  768. if !bytes.Equal(left.Hash.Bytes(), right.Hash.Bytes()) {
  769. return false
  770. }
  771. if left.Time != right.Time {
  772. return false
  773. }
  774. if len(left.Results) != len(right.Results) {
  775. return false
  776. }
  777. for idx := range left.Results {
  778. if !bytes.Equal(left.Results[idx], right.Results[idx]) {
  779. return false
  780. }
  781. }
  782. return true
  783. }
  784. //
  785. // Implementation of SolanaAccountQueryResponse, which implements the ChainSpecificResponse for a Solana sol_account query response.
  786. //
  787. func (sar *SolanaAccountQueryResponse) Type() ChainSpecificQueryType {
  788. return SolanaAccountQueryRequestType
  789. }
  790. // Marshal serializes the binary representation of a Solana sol_account response.
  791. // This method calls Validate() and relies on it to range check lengths, etc.
  792. func (sar *SolanaAccountQueryResponse) Marshal() ([]byte, error) {
  793. if err := sar.Validate(); err != nil {
  794. return nil, err
  795. }
  796. buf := new(bytes.Buffer)
  797. vaa.MustWrite(buf, binary.BigEndian, sar.SlotNumber)
  798. vaa.MustWrite(buf, binary.BigEndian, sar.BlockTime.UnixMicro())
  799. buf.Write(sar.BlockHash[:])
  800. vaa.MustWrite(buf, binary.BigEndian, uint8(len(sar.Results))) // #nosec G115 -- This is validated in `Validate`
  801. for _, res := range sar.Results {
  802. vaa.MustWrite(buf, binary.BigEndian, res.Lamports)
  803. vaa.MustWrite(buf, binary.BigEndian, res.RentEpoch)
  804. vaa.MustWrite(buf, binary.BigEndian, res.Executable)
  805. buf.Write(res.Owner[:])
  806. vaa.MustWrite(buf, binary.BigEndian, uint32(len(res.Data))) // #nosec G115 -- This is validated in `Validate`
  807. buf.Write(res.Data)
  808. }
  809. return buf.Bytes(), nil
  810. }
  811. // Unmarshal deserializes a Solana sol_account response from a byte array
  812. func (sar *SolanaAccountQueryResponse) Unmarshal(data []byte) error {
  813. reader := bytes.NewReader(data[:])
  814. return sar.UnmarshalFromReader(reader)
  815. }
  816. // UnmarshalFromReader deserializes a Solana sol_account response from a byte array
  817. func (sar *SolanaAccountQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  818. if err := binary.Read(reader, binary.BigEndian, &sar.SlotNumber); err != nil {
  819. return fmt.Errorf("failed to read slot number: %w", err)
  820. }
  821. blockTime := int64(0)
  822. if err := binary.Read(reader, binary.BigEndian, &blockTime); err != nil {
  823. return fmt.Errorf("failed to read block time: %w", err)
  824. }
  825. sar.BlockTime = time.UnixMicro(blockTime)
  826. if n, err := reader.Read(sar.BlockHash[:]); err != nil || n != SolanaPublicKeyLength {
  827. return fmt.Errorf("failed to read block hash [%d]: %w", n, err)
  828. }
  829. numResults := uint8(0)
  830. if err := binary.Read(reader, binary.BigEndian, &numResults); err != nil {
  831. return fmt.Errorf("failed to read number of results: %w", err)
  832. }
  833. for count := 0; count < int(numResults); count++ {
  834. var result SolanaAccountResult
  835. if err := binary.Read(reader, binary.BigEndian, &result.Lamports); err != nil {
  836. return fmt.Errorf("failed to read lamports: %w", err)
  837. }
  838. if err := binary.Read(reader, binary.BigEndian, &result.RentEpoch); err != nil {
  839. return fmt.Errorf("failed to read rent epoch: %w", err)
  840. }
  841. if err := binary.Read(reader, binary.BigEndian, &result.Executable); err != nil {
  842. return fmt.Errorf("failed to read executable flag: %w", err)
  843. }
  844. if n, err := reader.Read(result.Owner[:]); err != nil || n != SolanaPublicKeyLength {
  845. return fmt.Errorf("failed to read owner [%d]: %w", n, err)
  846. }
  847. length := uint32(0)
  848. if err := binary.Read(reader, binary.BigEndian, &length); err != nil {
  849. return fmt.Errorf("failed to read data len: %w", err)
  850. }
  851. result.Data = make([]byte, length)
  852. if n, err := reader.Read(result.Data[:]); err != nil || n != int(length) {
  853. return fmt.Errorf("failed to read data [%d]: %w", n, err)
  854. }
  855. sar.Results = append(sar.Results, result)
  856. }
  857. return nil
  858. }
  859. // Validate does basic validation on a Solana sol_account response.
  860. func (sar *SolanaAccountQueryResponse) Validate() error {
  861. // Not checking for SlotNumber == 0, because maybe that could happen??
  862. // Not checking for BlockTime == 0, because maybe that could happen??
  863. // The block hash is fixed length, so don't need to check for nil.
  864. if len(sar.BlockHash) != SolanaPublicKeyLength {
  865. return fmt.Errorf("invalid block hash length")
  866. }
  867. if len(sar.Results) <= 0 {
  868. return fmt.Errorf("does not contain any results")
  869. }
  870. if len(sar.Results) > math.MaxUint8 {
  871. return fmt.Errorf("too many results")
  872. }
  873. for _, result := range sar.Results {
  874. // Owner is fixed length, so don't need to check for nil.
  875. if len(result.Owner) != SolanaPublicKeyLength {
  876. return fmt.Errorf("invalid owner length")
  877. }
  878. if len(result.Data) > math.MaxUint32 {
  879. return fmt.Errorf("data too long")
  880. }
  881. }
  882. return nil
  883. }
  884. // Equal verifies that two Solana sol_account responses are equal.
  885. func (left *SolanaAccountQueryResponse) Equal(right *SolanaAccountQueryResponse) bool {
  886. if left.SlotNumber != right.SlotNumber ||
  887. left.BlockTime != right.BlockTime ||
  888. !bytes.Equal(left.BlockHash[:], right.BlockHash[:]) {
  889. return false
  890. }
  891. if len(left.Results) != len(right.Results) {
  892. return false
  893. }
  894. for idx := range left.Results {
  895. if left.Results[idx].Lamports != right.Results[idx].Lamports ||
  896. left.Results[idx].RentEpoch != right.Results[idx].RentEpoch ||
  897. left.Results[idx].Executable != right.Results[idx].Executable ||
  898. !bytes.Equal(left.Results[idx].Owner[:], right.Results[idx].Owner[:]) ||
  899. !bytes.Equal(left.Results[idx].Data, right.Results[idx].Data) {
  900. return false
  901. }
  902. }
  903. return true
  904. }
  905. //
  906. // Implementation of SolanaPdaQueryResponse, which implements the ChainSpecificResponse for a Solana sol_pda query response.
  907. //
  908. func (sar *SolanaPdaQueryResponse) Type() ChainSpecificQueryType {
  909. return SolanaPdaQueryRequestType
  910. }
  911. // Marshal serializes the binary representation of a Solana sol_pda response.
  912. // This method calls Validate() and relies on it to range check lengths, etc.
  913. func (sar *SolanaPdaQueryResponse) Marshal() ([]byte, error) {
  914. if err := sar.Validate(); err != nil {
  915. return nil, err
  916. }
  917. buf := new(bytes.Buffer)
  918. vaa.MustWrite(buf, binary.BigEndian, sar.SlotNumber)
  919. vaa.MustWrite(buf, binary.BigEndian, sar.BlockTime.UnixMicro())
  920. buf.Write(sar.BlockHash[:])
  921. vaa.MustWrite(buf, binary.BigEndian, uint8(len(sar.Results))) // #nosec G115 -- This is validated in `Validate`
  922. for _, res := range sar.Results {
  923. buf.Write(res.Account[:])
  924. vaa.MustWrite(buf, binary.BigEndian, res.Bump)
  925. vaa.MustWrite(buf, binary.BigEndian, res.Lamports)
  926. vaa.MustWrite(buf, binary.BigEndian, res.RentEpoch)
  927. vaa.MustWrite(buf, binary.BigEndian, res.Executable)
  928. buf.Write(res.Owner[:])
  929. vaa.MustWrite(buf, binary.BigEndian, uint32(len(res.Data))) // #nosec G115 -- This is validated in `Validate`
  930. buf.Write(res.Data)
  931. }
  932. return buf.Bytes(), nil
  933. }
  934. // Unmarshal deserializes a Solana sol_pda response from a byte array
  935. func (sar *SolanaPdaQueryResponse) Unmarshal(data []byte) error {
  936. reader := bytes.NewReader(data[:])
  937. return sar.UnmarshalFromReader(reader)
  938. }
  939. // UnmarshalFromReader deserializes a Solana sol_pda response from a byte array
  940. func (sar *SolanaPdaQueryResponse) UnmarshalFromReader(reader *bytes.Reader) error {
  941. if err := binary.Read(reader, binary.BigEndian, &sar.SlotNumber); err != nil {
  942. return fmt.Errorf("failed to read slot number: %w", err)
  943. }
  944. blockTime := int64(0)
  945. if err := binary.Read(reader, binary.BigEndian, &blockTime); err != nil {
  946. return fmt.Errorf("failed to read block time: %w", err)
  947. }
  948. sar.BlockTime = time.UnixMicro(blockTime)
  949. if n, err := reader.Read(sar.BlockHash[:]); err != nil || n != SolanaPublicKeyLength {
  950. return fmt.Errorf("failed to read block hash [%d]: %w", n, err)
  951. }
  952. numResults := uint8(0)
  953. if err := binary.Read(reader, binary.BigEndian, &numResults); err != nil {
  954. return fmt.Errorf("failed to read number of results: %w", err)
  955. }
  956. for count := 0; count < int(numResults); count++ {
  957. var result SolanaPdaResult
  958. if n, err := reader.Read(result.Account[:]); err != nil || n != SolanaPublicKeyLength {
  959. return fmt.Errorf("failed to read account [%d]: %w", n, err)
  960. }
  961. if err := binary.Read(reader, binary.BigEndian, &result.Bump); err != nil {
  962. return fmt.Errorf("failed to read bump: %w", err)
  963. }
  964. if err := binary.Read(reader, binary.BigEndian, &result.Lamports); err != nil {
  965. return fmt.Errorf("failed to read lamports: %w", err)
  966. }
  967. if err := binary.Read(reader, binary.BigEndian, &result.RentEpoch); err != nil {
  968. return fmt.Errorf("failed to read rent epoch: %w", err)
  969. }
  970. if err := binary.Read(reader, binary.BigEndian, &result.Executable); err != nil {
  971. return fmt.Errorf("failed to read executable flag: %w", err)
  972. }
  973. if n, err := reader.Read(result.Owner[:]); err != nil || n != SolanaPublicKeyLength {
  974. return fmt.Errorf("failed to read owner [%d]: %w", n, err)
  975. }
  976. length := uint32(0)
  977. if err := binary.Read(reader, binary.BigEndian, &length); err != nil {
  978. return fmt.Errorf("failed to read data len: %w", err)
  979. }
  980. result.Data = make([]byte, length)
  981. if n, err := reader.Read(result.Data[:]); err != nil || n != int(length) {
  982. return fmt.Errorf("failed to read data [%d]: %w", n, err)
  983. }
  984. sar.Results = append(sar.Results, result)
  985. }
  986. return nil
  987. }
  988. // Validate does basic validation on a Solana sol_pda response.
  989. func (sar *SolanaPdaQueryResponse) Validate() error {
  990. // Not checking for SlotNumber == 0, because maybe that could happen??
  991. // Not checking for BlockTime == 0, because maybe that could happen??
  992. // The block hash is fixed length, so don't need to check for nil.
  993. if len(sar.BlockHash) != SolanaPublicKeyLength {
  994. return fmt.Errorf("invalid block hash length")
  995. }
  996. if len(sar.Results) <= 0 {
  997. return fmt.Errorf("does not contain any results")
  998. }
  999. if len(sar.Results) > math.MaxUint8 {
  1000. return fmt.Errorf("too many results")
  1001. }
  1002. for _, result := range sar.Results {
  1003. // Account is fixed length, so don't need to check for nil.
  1004. if len(result.Account) != SolanaPublicKeyLength {
  1005. return fmt.Errorf("invalid account length")
  1006. }
  1007. // Owner is fixed length, so don't need to check for nil.
  1008. if len(result.Owner) != SolanaPublicKeyLength {
  1009. return fmt.Errorf("invalid owner length")
  1010. }
  1011. if len(result.Data) > math.MaxUint32 {
  1012. return fmt.Errorf("data too long")
  1013. }
  1014. }
  1015. return nil
  1016. }
  1017. // Equal verifies that two Solana sol_pda responses are equal.
  1018. func (left *SolanaPdaQueryResponse) Equal(right *SolanaPdaQueryResponse) bool {
  1019. if left.SlotNumber != right.SlotNumber ||
  1020. left.BlockTime != right.BlockTime ||
  1021. !bytes.Equal(left.BlockHash[:], right.BlockHash[:]) {
  1022. return false
  1023. }
  1024. if len(left.Results) != len(right.Results) {
  1025. return false
  1026. }
  1027. for idx := range left.Results {
  1028. if !bytes.Equal(left.Results[idx].Account[:], right.Results[idx].Account[:]) ||
  1029. left.Results[idx].Bump != right.Results[idx].Bump ||
  1030. left.Results[idx].Lamports != right.Results[idx].Lamports ||
  1031. left.Results[idx].RentEpoch != right.Results[idx].RentEpoch ||
  1032. left.Results[idx].Executable != right.Results[idx].Executable ||
  1033. !bytes.Equal(left.Results[idx].Owner[:], right.Results[idx].Owner[:]) ||
  1034. !bytes.Equal(left.Results[idx].Data, right.Results[idx].Data) {
  1035. return false
  1036. }
  1037. }
  1038. return true
  1039. }