github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/jsonrpc/types/types.go (about) 1 package types 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "math/big" 8 "strconv" 9 "strings" 10 11 "github.com/0xPolygon/supernets2-node/hex" 12 "github.com/0xPolygon/supernets2-node/state" 13 "github.com/ethereum/go-ethereum/common" 14 "github.com/ethereum/go-ethereum/core/types" 15 "github.com/jackc/pgx/v4" 16 ) 17 18 // ArgUint64 helps to marshal uint64 values provided in the RPC requests 19 type ArgUint64 uint64 20 21 // MarshalText marshals into text 22 func (b ArgUint64) MarshalText() ([]byte, error) { 23 buf := make([]byte, 2) //nolint:gomnd 24 copy(buf, `0x`) 25 buf = strconv.AppendUint(buf, uint64(b), hex.Base) 26 return buf, nil 27 } 28 29 // UnmarshalText unmarshals from text 30 func (b *ArgUint64) UnmarshalText(input []byte) error { 31 str := strings.TrimPrefix(string(input), "0x") 32 num, err := strconv.ParseUint(str, hex.Base, hex.BitSize64) 33 if err != nil { 34 return err 35 } 36 *b = ArgUint64(num) 37 return nil 38 } 39 40 // Hex returns a hexadecimal representation 41 func (b ArgUint64) Hex() string { 42 bb, _ := b.MarshalText() 43 return string(bb) 44 } 45 46 // ArgUint64Ptr returns the pointer of the provided ArgUint64 47 func ArgUint64Ptr(a ArgUint64) *ArgUint64 { 48 return &a 49 } 50 51 // ArgBytes helps to marshal byte array values provided in the RPC requests 52 type ArgBytes []byte 53 54 // MarshalText marshals into text 55 func (b ArgBytes) MarshalText() ([]byte, error) { 56 return encodeToHex(b), nil 57 } 58 59 // UnmarshalText unmarshals from text 60 func (b *ArgBytes) UnmarshalText(input []byte) error { 61 hh, err := decodeToHex(input) 62 if err != nil { 63 return nil 64 } 65 aux := make([]byte, len(hh)) 66 copy(aux[:], hh[:]) 67 *b = aux 68 return nil 69 } 70 71 // Hex returns a hexadecimal representation 72 func (b ArgBytes) Hex() string { 73 bb, _ := b.MarshalText() 74 return string(bb) 75 } 76 77 // ArgBytesPtr helps to marshal byte array values provided in the RPC requests 78 func ArgBytesPtr(b []byte) *ArgBytes { 79 bb := ArgBytes(b) 80 81 return &bb 82 } 83 84 // ArgBig helps to marshal big number values provided in the RPC requests 85 type ArgBig big.Int 86 87 // UnmarshalText unmarshals an instance of ArgBig into an array of bytes 88 func (a *ArgBig) UnmarshalText(input []byte) error { 89 buf, err := decodeToHex(input) 90 if err != nil { 91 return err 92 } 93 94 b := new(big.Int) 95 b.SetBytes(buf) 96 *a = ArgBig(*b) 97 98 return nil 99 } 100 101 // MarshalText marshals an array of bytes into an instance of ArgBig 102 func (a ArgBig) MarshalText() ([]byte, error) { 103 b := (*big.Int)(&a) 104 105 return []byte("0x" + b.Text(hex.Base)), nil 106 } 107 108 // Hex returns a hexadecimal representation 109 func (b ArgBig) Hex() string { 110 bb, _ := b.MarshalText() 111 return string(bb) 112 } 113 114 func decodeToHex(b []byte) ([]byte, error) { 115 str := string(b) 116 str = strings.TrimPrefix(str, "0x") 117 if len(str)%2 != 0 { 118 str = "0" + str 119 } 120 return hex.DecodeString(str) 121 } 122 123 func encodeToHex(b []byte) []byte { 124 str := hex.EncodeToString(b) 125 if len(str)%2 != 0 { 126 str = "0" + str 127 } 128 return []byte("0x" + str) 129 } 130 131 // ArgHash represents a common.Hash that accepts strings 132 // shorter than 64 bytes, like 0x00 133 type ArgHash common.Hash 134 135 // UnmarshalText unmarshals from text 136 func (arg *ArgHash) UnmarshalText(input []byte) error { 137 if !hex.IsValid(string(input)) { 138 return fmt.Errorf("invalid hash, it needs to be a hexadecimal value") 139 } 140 141 str := strings.TrimPrefix(string(input), "0x") 142 *arg = ArgHash(common.HexToHash(str)) 143 return nil 144 } 145 146 // Hash returns an instance of common.Hash 147 func (arg *ArgHash) Hash() common.Hash { 148 result := common.Hash{} 149 if arg != nil { 150 result = common.Hash(*arg) 151 } 152 return result 153 } 154 155 // ArgAddress represents a common.Address that accepts strings 156 // shorter than 32 bytes, like 0x00 157 type ArgAddress common.Address 158 159 // UnmarshalText unmarshals from text 160 func (b *ArgAddress) UnmarshalText(input []byte) error { 161 if !hex.IsValid(string(input)) { 162 return fmt.Errorf("invalid address, it needs to be a hexadecimal value") 163 } 164 165 str := strings.TrimPrefix(string(input), "0x") 166 *b = ArgAddress(common.HexToAddress(str)) 167 return nil 168 } 169 170 // Address returns an instance of common.Address 171 func (arg *ArgAddress) Address() common.Address { 172 result := common.Address{} 173 if arg != nil { 174 result = common.Address(*arg) 175 } 176 return result 177 } 178 179 // TxArgs is the transaction argument for the rpc endpoints 180 type TxArgs struct { 181 From *common.Address 182 To *common.Address 183 Gas *ArgUint64 184 GasPrice *ArgBytes 185 Value *ArgBytes 186 Data *ArgBytes 187 Input *ArgBytes 188 Nonce *ArgUint64 189 } 190 191 // ToTransaction transforms txnArgs into a Transaction 192 func (args *TxArgs) ToTransaction(ctx context.Context, st StateInterface, maxCumulativeGasUsed uint64, root common.Hash, defaultSenderAddress common.Address, dbTx pgx.Tx) (common.Address, *types.Transaction, error) { 193 sender := defaultSenderAddress 194 nonce := uint64(0) 195 if args.From != nil && *args.From != state.ZeroAddress { 196 sender = *args.From 197 n, err := st.GetNonce(ctx, sender, root) 198 if err != nil { 199 return common.Address{}, nil, err 200 } 201 nonce = n 202 } 203 204 value := big.NewInt(0) 205 if args.Value != nil { 206 value.SetBytes(*args.Value) 207 } 208 209 gasPrice := big.NewInt(0) 210 if args.GasPrice != nil { 211 gasPrice.SetBytes(*args.GasPrice) 212 } 213 214 var data []byte 215 if args.Data != nil { 216 data = *args.Data 217 } else if args.Input != nil { 218 data = *args.Input 219 } else if args.To == nil { 220 return common.Address{}, nil, fmt.Errorf("contract creation without data provided") 221 } 222 223 gas := maxCumulativeGasUsed 224 if args.Gas != nil && uint64(*args.Gas) > 0 && uint64(*args.Gas) < maxCumulativeGasUsed { 225 gas = uint64(*args.Gas) 226 } 227 228 tx := types.NewTx(&types.LegacyTx{ 229 Nonce: nonce, 230 To: args.To, 231 Value: value, 232 Gas: gas, 233 GasPrice: gasPrice, 234 Data: data, 235 }) 236 237 return sender, tx, nil 238 } 239 240 // Block structure 241 type Block struct { 242 ParentHash common.Hash `json:"parentHash"` 243 Sha3Uncles common.Hash `json:"sha3Uncles"` 244 Miner common.Address `json:"miner"` 245 StateRoot common.Hash `json:"stateRoot"` 246 TxRoot common.Hash `json:"transactionsRoot"` 247 ReceiptsRoot common.Hash `json:"receiptsRoot"` 248 LogsBloom types.Bloom `json:"logsBloom"` 249 Difficulty ArgUint64 `json:"difficulty"` 250 TotalDifficulty ArgUint64 `json:"totalDifficulty"` 251 Size ArgUint64 `json:"size"` 252 Number ArgUint64 `json:"number"` 253 GasLimit ArgUint64 `json:"gasLimit"` 254 GasUsed ArgUint64 `json:"gasUsed"` 255 Timestamp ArgUint64 `json:"timestamp"` 256 ExtraData ArgBytes `json:"extraData"` 257 MixHash common.Hash `json:"mixHash"` 258 Nonce ArgBytes `json:"nonce"` 259 Hash common.Hash `json:"hash"` 260 Transactions []TransactionOrHash `json:"transactions"` 261 Uncles []common.Hash `json:"uncles"` 262 } 263 264 // NewBlock creates a Block instance 265 func NewBlock(b *types.Block, fullTx bool) *Block { 266 h := b.Header() 267 268 n := big.NewInt(0).SetUint64(h.Nonce.Uint64()) 269 nonce := common.LeftPadBytes(n.Bytes(), 8) //nolint:gomnd 270 271 var difficulty uint64 272 if h.Difficulty != nil { 273 difficulty = h.Difficulty.Uint64() 274 } else { 275 difficulty = uint64(0) 276 } 277 278 res := &Block{ 279 ParentHash: h.ParentHash, 280 Sha3Uncles: h.UncleHash, 281 Miner: h.Coinbase, 282 StateRoot: h.Root, 283 TxRoot: h.TxHash, 284 ReceiptsRoot: h.ReceiptHash, 285 LogsBloom: h.Bloom, 286 Difficulty: ArgUint64(difficulty), 287 TotalDifficulty: ArgUint64(difficulty), 288 Size: ArgUint64(b.Size()), 289 Number: ArgUint64(b.Number().Uint64()), 290 GasLimit: ArgUint64(h.GasLimit), 291 GasUsed: ArgUint64(h.GasUsed), 292 Timestamp: ArgUint64(h.Time), 293 ExtraData: ArgBytes(h.Extra), 294 MixHash: h.MixDigest, 295 Nonce: nonce, 296 Hash: b.Hash(), 297 Transactions: []TransactionOrHash{}, 298 Uncles: []common.Hash{}, 299 } 300 301 for idx, txn := range b.Transactions() { 302 if fullTx { 303 blockHash := b.Hash() 304 txIndex := uint64(idx) 305 tx := NewTransaction(*txn, b.Number(), &blockHash, &txIndex) 306 res.Transactions = append( 307 res.Transactions, 308 TransactionOrHash{Tx: tx}, 309 ) 310 } else { 311 h := txn.Hash() 312 res.Transactions = append( 313 res.Transactions, 314 TransactionOrHash{Hash: &h}, 315 ) 316 } 317 } 318 319 for _, uncle := range b.Uncles() { 320 res.Uncles = append(res.Uncles, uncle.Hash()) 321 } 322 323 return res 324 } 325 326 // Batch structure 327 type Batch struct { 328 Number ArgUint64 `json:"number"` 329 Coinbase common.Address `json:"coinbase"` 330 StateRoot common.Hash `json:"stateRoot"` 331 GlobalExitRoot common.Hash `json:"globalExitRoot"` 332 MainnetExitRoot common.Hash `json:"mainnetExitRoot"` 333 RollupExitRoot common.Hash `json:"rollupExitRoot"` 334 LocalExitRoot common.Hash `json:"localExitRoot"` 335 AccInputHash common.Hash `json:"accInputHash"` 336 Timestamp ArgUint64 `json:"timestamp"` 337 SendSequencesTxHash *common.Hash `json:"sendSequencesTxHash"` 338 VerifyBatchTxHash *common.Hash `json:"verifyBatchTxHash"` 339 Transactions []TransactionOrHash `json:"transactions"` 340 BatchL2Data ArgBytes `json:"batchL2Data"` 341 } 342 343 // NewBatch creates a Batch instance 344 func NewBatch( 345 batch *state.Batch, 346 virtualBatch *state.VirtualBatch, 347 verifiedBatch *state.VerifiedBatch, 348 receipts []types.Receipt, 349 fullTx bool, 350 ger *state.GlobalExitRoot, 351 ) (*Batch, error) { 352 batchL2Data := batch.BatchL2Data 353 if batchL2Data == nil { 354 batchL2dataFromTxs, err := state.EncodeTransactions(batch.Transactions) 355 if err != nil { 356 return nil, fmt.Errorf("error encoding txs into raw data: %w", err) 357 } else { 358 batchL2Data = batchL2dataFromTxs 359 } 360 } 361 res := &Batch{ 362 Number: ArgUint64(batch.BatchNumber), 363 GlobalExitRoot: batch.GlobalExitRoot, 364 MainnetExitRoot: ger.MainnetExitRoot, 365 RollupExitRoot: ger.RollupExitRoot, 366 AccInputHash: batch.AccInputHash, 367 Timestamp: ArgUint64(batch.Timestamp.Unix()), 368 StateRoot: batch.StateRoot, 369 Coinbase: batch.Coinbase, 370 LocalExitRoot: batch.LocalExitRoot, 371 BatchL2Data: ArgBytes(batchL2Data), 372 } 373 374 if virtualBatch != nil { 375 res.SendSequencesTxHash = &virtualBatch.TxHash 376 } 377 378 if verifiedBatch != nil { 379 res.VerifyBatchTxHash = &verifiedBatch.TxHash 380 } 381 382 receiptsMap := make(map[common.Hash]types.Receipt, len(receipts)) 383 for _, receipt := range receipts { 384 receiptsMap[receipt.TxHash] = receipt 385 } 386 387 for _, tx := range batch.Transactions { 388 if fullTx { 389 receipt := receiptsMap[tx.Hash()] 390 txIndex := uint64(receipt.TransactionIndex) 391 rpcTx := NewTransaction(tx, receipt.BlockNumber, &receipt.BlockHash, &txIndex) 392 res.Transactions = append(res.Transactions, TransactionOrHash{Tx: rpcTx}) 393 } else { 394 h := tx.Hash() 395 res.Transactions = append(res.Transactions, TransactionOrHash{Hash: &h}) 396 } 397 } 398 399 return res, nil 400 } 401 402 // TransactionOrHash for union type of transaction and types.Hash 403 type TransactionOrHash struct { 404 Hash *common.Hash 405 Tx *Transaction 406 } 407 408 // MarshalJSON marshals into json 409 func (b TransactionOrHash) MarshalJSON() ([]byte, error) { 410 if b.Hash != nil { 411 return json.Marshal(b.Hash) 412 } 413 return json.Marshal(b.Tx) 414 } 415 416 // UnmarshalJSON unmarshals from json 417 func (b *TransactionOrHash) UnmarshalJSON(input []byte) error { 418 v := string(input) 419 if strings.HasPrefix(v, "0x") || strings.HasPrefix(v, "\"0x") { 420 var h common.Hash 421 err := json.Unmarshal(input, &h) 422 if err != nil { 423 return err 424 } 425 *b = TransactionOrHash{Hash: &h} 426 return nil 427 } 428 429 var t Transaction 430 err := json.Unmarshal(input, &t) 431 if err != nil { 432 return err 433 } 434 *b = TransactionOrHash{Tx: &t} 435 return nil 436 } 437 438 // Transaction structure 439 type Transaction struct { 440 Nonce ArgUint64 `json:"nonce"` 441 GasPrice ArgBig `json:"gasPrice"` 442 Gas ArgUint64 `json:"gas"` 443 To *common.Address `json:"to"` 444 Value ArgBig `json:"value"` 445 Input ArgBytes `json:"input"` 446 V ArgBig `json:"v"` 447 R ArgBig `json:"r"` 448 S ArgBig `json:"s"` 449 Hash common.Hash `json:"hash"` 450 From common.Address `json:"from"` 451 BlockHash *common.Hash `json:"blockHash"` 452 BlockNumber *ArgUint64 `json:"blockNumber"` 453 TxIndex *ArgUint64 `json:"transactionIndex"` 454 ChainID ArgBig `json:"chainId"` 455 Type ArgUint64 `json:"type"` 456 } 457 458 // CoreTx returns a geth core type Transaction 459 func (t Transaction) CoreTx() *types.Transaction { 460 return types.NewTx(&types.LegacyTx{ 461 Nonce: uint64(t.Nonce), 462 GasPrice: (*big.Int)(&t.GasPrice), 463 Gas: uint64(t.Gas), 464 To: t.To, 465 Value: (*big.Int)(&t.Value), 466 Data: t.Input, 467 V: (*big.Int)(&t.V), 468 R: (*big.Int)(&t.R), 469 S: (*big.Int)(&t.S), 470 }) 471 } 472 473 // NewTransaction creates a transaction instance 474 func NewTransaction( 475 t types.Transaction, 476 blockNumber *big.Int, 477 blockHash *common.Hash, 478 txIndex *uint64, 479 ) *Transaction { 480 v, r, s := t.RawSignatureValues() 481 482 from, _ := state.GetSender(t) 483 484 res := &Transaction{ 485 Nonce: ArgUint64(t.Nonce()), 486 GasPrice: ArgBig(*t.GasPrice()), 487 Gas: ArgUint64(t.Gas()), 488 To: t.To(), 489 Value: ArgBig(*t.Value()), 490 Input: t.Data(), 491 V: ArgBig(*v), 492 R: ArgBig(*r), 493 S: ArgBig(*s), 494 Hash: t.Hash(), 495 From: from, 496 ChainID: ArgBig(*t.ChainId()), 497 Type: ArgUint64(t.Type()), 498 } 499 500 if blockNumber != nil { 501 bn := ArgUint64(blockNumber.Uint64()) 502 res.BlockNumber = &bn 503 } 504 505 res.BlockHash = blockHash 506 507 if txIndex != nil { 508 ti := ArgUint64(*txIndex) 509 res.TxIndex = &ti 510 } 511 512 return res 513 } 514 515 // Receipt structure 516 type Receipt struct { 517 Root common.Hash `json:"root"` 518 CumulativeGasUsed ArgUint64 `json:"cumulativeGasUsed"` 519 LogsBloom types.Bloom `json:"logsBloom"` 520 Logs []*types.Log `json:"logs"` 521 Status ArgUint64 `json:"status"` 522 TxHash common.Hash `json:"transactionHash"` 523 TxIndex ArgUint64 `json:"transactionIndex"` 524 BlockHash common.Hash `json:"blockHash"` 525 BlockNumber ArgUint64 `json:"blockNumber"` 526 GasUsed ArgUint64 `json:"gasUsed"` 527 FromAddr common.Address `json:"from"` 528 ToAddr *common.Address `json:"to"` 529 ContractAddress *common.Address `json:"contractAddress"` 530 Type ArgUint64 `json:"type"` 531 } 532 533 // NewReceipt creates a new Receipt instance 534 func NewReceipt(tx types.Transaction, r *types.Receipt) (Receipt, error) { 535 to := tx.To() 536 logs := r.Logs 537 if logs == nil { 538 logs = []*types.Log{} 539 } 540 541 var contractAddress *common.Address 542 if r.ContractAddress != state.ZeroAddress { 543 ca := r.ContractAddress 544 contractAddress = &ca 545 } 546 547 blockNumber := ArgUint64(0) 548 if r.BlockNumber != nil { 549 blockNumber = ArgUint64(r.BlockNumber.Uint64()) 550 } 551 552 from, err := state.GetSender(tx) 553 if err != nil { 554 return Receipt{}, err 555 } 556 557 return Receipt{ 558 Root: common.BytesToHash(r.PostState), 559 CumulativeGasUsed: ArgUint64(r.CumulativeGasUsed), 560 LogsBloom: r.Bloom, 561 Logs: logs, 562 Status: ArgUint64(r.Status), 563 TxHash: r.TxHash, 564 TxIndex: ArgUint64(r.TransactionIndex), 565 BlockHash: r.BlockHash, 566 BlockNumber: blockNumber, 567 GasUsed: ArgUint64(r.GasUsed), 568 ContractAddress: contractAddress, 569 FromAddr: from, 570 ToAddr: to, 571 Type: ArgUint64(r.Type), 572 }, nil 573 } 574 575 // Log structure 576 type Log struct { 577 Address common.Address `json:"address"` 578 Topics []common.Hash `json:"topics"` 579 Data ArgBytes `json:"data"` 580 BlockNumber ArgUint64 `json:"blockNumber"` 581 TxHash common.Hash `json:"transactionHash"` 582 TxIndex ArgUint64 `json:"transactionIndex"` 583 BlockHash common.Hash `json:"blockHash"` 584 LogIndex ArgUint64 `json:"logIndex"` 585 Removed bool `json:"removed"` 586 } 587 588 // NewLog creates a new instance of Log 589 func NewLog(l types.Log) Log { 590 return Log{ 591 Address: l.Address, 592 Topics: l.Topics, 593 Data: l.Data, 594 BlockNumber: ArgUint64(l.BlockNumber), 595 TxHash: l.TxHash, 596 TxIndex: ArgUint64(l.TxIndex), 597 BlockHash: l.BlockHash, 598 LogIndex: ArgUint64(l.Index), 599 Removed: l.Removed, 600 } 601 } 602 603 // ToBatchNumArg converts a big.Int into a batch number rpc parameter 604 func ToBatchNumArg(number *big.Int) string { 605 if number == nil { 606 return Latest 607 } 608 pending := big.NewInt(-1) 609 if number.Cmp(pending) == 0 { 610 return Pending 611 } 612 return hex.EncodeBig(number) 613 }