github.com/iotexproject/iotex-core@v1.14.1-rc1/api/web3server_marshal.go (about) 1 package api 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 7 "github.com/ethereum/go-ethereum/common/hexutil" 8 "github.com/ethereum/go-ethereum/core/types" 9 "github.com/iotexproject/go-pkgs/crypto" 10 "github.com/iotexproject/go-pkgs/hash" 11 "github.com/iotexproject/iotex-address/address" 12 "github.com/pkg/errors" 13 "google.golang.org/grpc/status" 14 "google.golang.org/protobuf/types/known/timestamppb" 15 16 "github.com/iotexproject/iotex-core/action" 17 apitypes "github.com/iotexproject/iotex-core/api/types" 18 "github.com/iotexproject/iotex-core/blockchain/block" 19 ) 20 21 const ( 22 _zeroLogsBloom = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 23 ) 24 25 type ( 26 web3Response struct { 27 id any 28 result interface{} 29 err error 30 } 31 32 errMessage struct { 33 Code int `json:"code"` 34 Message string `json:"message"` 35 Data interface{} `json:"data,omitempty"` 36 } 37 38 streamResponse struct { 39 id string 40 result interface{} 41 } 42 43 streamParams struct { 44 Subscription string `json:"subscription"` 45 Result interface{} `json:"result"` 46 } 47 48 getBlockResult struct { 49 blk *block.Block 50 transactions []interface{} 51 } 52 53 getTransactionResult struct { 54 blockHash *hash.Hash256 55 to *string 56 ethTx *types.Transaction 57 receipt *action.Receipt 58 pubkey crypto.PublicKey 59 } 60 61 getReceiptResult struct { 62 blockHash hash.Hash256 63 from address.Address 64 to *string 65 contractAddress *string 66 logsBloom string 67 receipt *action.Receipt 68 } 69 70 getLogsResult struct { 71 blockHash hash.Hash256 72 log *action.Log 73 } 74 75 getSyncingResult struct { 76 StartingBlock string `json:"startingBlock"` 77 CurrentBlock string `json:"currentBlock"` 78 HighestBlock string `json:"highestBlock"` 79 } 80 81 debugTraceTransactionResult struct { 82 Failed bool `json:"failed"` 83 Revert string `json:"revert"` 84 ReturnValue string `json:"returnValue"` 85 Gas uint64 `json:"gas"` 86 StructLogs []apitypes.StructLog `json:"structLogs"` 87 } 88 ) 89 90 var ( 91 errInvalidObject = errors.New("invalid object") 92 ) 93 94 func (obj *web3Response) MarshalJSON() ([]byte, error) { 95 if obj.err == nil { 96 return json.Marshal(&struct { 97 Jsonrpc string `json:"jsonrpc"` 98 ID any `json:"id"` 99 Result interface{} `json:"result"` 100 }{ 101 Jsonrpc: "2.0", 102 ID: obj.id, 103 Result: obj.result, 104 }) 105 } 106 107 var ( 108 errCode int 109 errMsg string 110 ) 111 // error code: https://eth.wiki/json-rpc/json-rpc-error-codes-improvement-proposal 112 if s, ok := status.FromError(obj.err); ok { 113 errCode, errMsg = int(s.Code()), s.Message() 114 } else { 115 errCode, errMsg = -32603, obj.err.Error() 116 } 117 118 return json.Marshal(&struct { 119 Jsonrpc string `json:"jsonrpc"` 120 ID any `json:"id"` 121 Error errMessage `json:"error"` 122 }{ 123 Jsonrpc: "2.0", 124 ID: obj.id, 125 Error: errMessage{ 126 Code: errCode, 127 Message: errMsg, 128 Data: obj.result, 129 }, 130 }) 131 } 132 133 func getLogsBloomHex(logsbloom string) string { 134 if len(logsbloom) == 0 { 135 return _zeroLogsBloom 136 } 137 return "0x" + logsbloom 138 } 139 140 func (obj *getBlockResult) MarshalJSON() ([]byte, error) { 141 if obj.blk == nil { 142 return nil, errInvalidObject 143 } 144 145 var ( 146 blkHash hash.Hash256 147 producerAddress string 148 logsBloomStr string 149 gasLimit, gasUsed uint64 150 151 txs = make([]interface{}, 0) 152 preHash = obj.blk.Header.PrevHash() 153 txRoot = obj.blk.Header.TxRoot() 154 deltaStateDigest = obj.blk.Header.DeltaStateDigest() 155 receiptRoot = obj.blk.Header.ReceiptRoot() 156 ) 157 if obj.blk.Height() > 0 { 158 producerAddress = obj.blk.Header.ProducerAddress() 159 blkHash = obj.blk.Header.HashBlock() 160 } else { 161 blkHash = block.GenesisHash() 162 } 163 producerAddr, err := ioAddrToEthAddr(producerAddress) 164 if err != nil { 165 return nil, err 166 } 167 for _, tx := range obj.blk.Actions { 168 gasLimit += tx.GasLimit() 169 } 170 for _, r := range obj.blk.Receipts { 171 gasUsed += r.GasConsumed 172 } 173 if logsBloom := obj.blk.Header.LogsBloomfilter(); logsBloom != nil { 174 logsBloomStr = hex.EncodeToString(logsBloom.Bytes()) 175 } 176 if len(obj.transactions) > 0 { 177 txs = obj.transactions 178 } 179 return json.Marshal(&struct { 180 Author string `json:"author"` 181 Number string `json:"number"` 182 Hash string `json:"hash"` 183 ParentHash string `json:"parentHash"` 184 Sha3Uncles string `json:"sha3Uncles"` 185 LogsBloom string `json:"logsBloom"` 186 TransactionsRoot string `json:"transactionsRoot"` 187 StateRoot string `json:"stateRoot"` 188 ReceiptsRoot string `json:"receiptsRoot"` 189 Miner string `json:"miner"` 190 Difficulty string `json:"difficulty"` 191 TotalDifficulty string `json:"totalDifficulty"` 192 ExtraData string `json:"extraData"` 193 Size string `json:"size"` 194 GasLimit string `json:"gasLimit"` 195 GasUsed string `json:"gasUsed"` 196 Timestamp string `json:"timestamp"` 197 Transactions []interface{} `json:"transactions"` 198 Step string `json:"step"` 199 Uncles []string `json:"uncles"` 200 }{ 201 Author: producerAddr, 202 Number: uint64ToHex(obj.blk.Height()), 203 Hash: "0x" + hex.EncodeToString(blkHash[:]), 204 ParentHash: "0x" + hex.EncodeToString(preHash[:]), 205 Sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 206 LogsBloom: getLogsBloomHex(logsBloomStr), 207 TransactionsRoot: "0x" + hex.EncodeToString(txRoot[:]), 208 StateRoot: "0x" + hex.EncodeToString(deltaStateDigest[:]), 209 ReceiptsRoot: "0x" + hex.EncodeToString(receiptRoot[:]), 210 Miner: producerAddr, 211 Difficulty: "0xfffffffffffffffffffffffffffffffe", 212 TotalDifficulty: "0xff14700000000000000000000000486001d72", 213 ExtraData: "0x", 214 Size: uint64ToHex(uint64(len(obj.blk.Actions))), 215 GasLimit: uint64ToHex(gasLimit), 216 GasUsed: uint64ToHex(gasUsed), 217 Timestamp: uint64ToHex(uint64(timestamppb.New(obj.blk.Header.Timestamp()).Seconds)), 218 Transactions: txs, 219 Step: "373422302", 220 Uncles: []string{}, 221 }) 222 } 223 224 func (obj *getTransactionResult) MarshalJSON() ([]byte, error) { 225 if obj.pubkey == nil || obj.ethTx == nil { 226 return nil, errInvalidObject 227 } 228 var ( 229 value, _ = intStrToHex(obj.ethTx.Value().String()) 230 gasPrice, _ = intStrToHex(obj.ethTx.GasPrice().String()) 231 v, r, s = obj.ethTx.RawSignatureValues() 232 txHash = obj.ethTx.Hash().Bytes() 233 blkNum *string 234 txIndex *string 235 blkHash *string 236 ) 237 238 if obj.receipt != nil { 239 txHash = obj.receipt.ActionHash[:] 240 } 241 if obj.receipt != nil { 242 tmp := uint64ToHex(obj.receipt.BlockHeight) 243 blkNum = &tmp 244 } 245 if obj.receipt != nil { 246 tmp := uint64ToHex(uint64(obj.receipt.TxIndex)) 247 txIndex = &tmp 248 } 249 if obj.blockHash != nil { 250 tmp := "0x" + hex.EncodeToString(obj.blockHash[:]) 251 blkHash = &tmp 252 } 253 return json.Marshal(&struct { 254 Hash string `json:"hash"` 255 Nonce string `json:"nonce"` 256 BlockHash *string `json:"blockHash"` 257 BlockNumber *string `json:"blockNumber"` 258 TransactionIndex *string `json:"transactionIndex"` 259 From string `json:"from"` 260 To *string `json:"to"` 261 Value string `json:"value"` 262 GasPrice string `json:"gasPrice"` 263 Gas string `json:"gas"` 264 Input string `json:"input"` 265 R string `json:"r"` 266 S string `json:"s"` 267 V string `json:"v"` 268 }{ 269 Hash: "0x" + hex.EncodeToString(txHash), 270 Nonce: uint64ToHex(obj.ethTx.Nonce()), 271 BlockHash: blkHash, 272 BlockNumber: blkNum, 273 TransactionIndex: txIndex, 274 From: obj.pubkey.Address().Hex(), 275 To: obj.to, 276 Value: value, 277 GasPrice: gasPrice, 278 Gas: uint64ToHex(obj.ethTx.Gas()), 279 Input: byteToHex(obj.ethTx.Data()), 280 R: hexutil.EncodeBig(r), 281 S: hexutil.EncodeBig(s), 282 V: hexutil.EncodeBig(v), 283 }) 284 } 285 286 func (obj *getReceiptResult) MarshalJSON() ([]byte, error) { 287 if obj.receipt == nil { 288 return nil, errInvalidObject 289 } 290 logs := make([]*getLogsResult, 0, len(obj.receipt.Logs())) 291 for _, v := range obj.receipt.Logs() { 292 logs = append(logs, &getLogsResult{obj.blockHash, v}) 293 } 294 295 return json.Marshal(&struct { 296 TransactionIndex string `json:"transactionIndex"` 297 TransactionHash string `json:"transactionHash"` 298 BlockHash string `json:"blockHash"` 299 BlockNumber string `json:"blockNumber"` 300 From string `json:"from"` 301 To *string `json:"to"` 302 CumulativeGasUsed string `json:"cumulativeGasUsed"` 303 GasUsed string `json:"gasUsed"` 304 ContractAddress *string `json:"contractAddress"` 305 LogsBloom string `json:"logsBloom"` 306 Logs []*getLogsResult `json:"logs"` 307 Status string `json:"status"` 308 }{ 309 TransactionIndex: uint64ToHex(uint64(obj.receipt.TxIndex)), 310 TransactionHash: "0x" + hex.EncodeToString(obj.receipt.ActionHash[:]), 311 BlockHash: "0x" + hex.EncodeToString(obj.blockHash[:]), 312 BlockNumber: uint64ToHex(obj.receipt.BlockHeight), 313 From: obj.from.Hex(), 314 To: obj.to, 315 CumulativeGasUsed: uint64ToHex(obj.receipt.GasConsumed), 316 GasUsed: uint64ToHex(obj.receipt.GasConsumed), 317 ContractAddress: obj.contractAddress, 318 LogsBloom: getLogsBloomHex(obj.logsBloom), 319 Logs: logs, 320 Status: uint64ToHex(obj.receipt.Status), 321 }) 322 } 323 324 func (obj *getLogsResult) MarshalJSON() ([]byte, error) { 325 if obj.log == nil { 326 return nil, errInvalidObject 327 } 328 addr, err := ioAddrToEthAddr(obj.log.Address) 329 if err != nil { 330 return nil, err 331 } 332 topics := make([]string, 0, len(obj.log.Topics)) 333 for _, tpc := range obj.log.Topics { 334 topics = append(topics, "0x"+hex.EncodeToString(tpc[:])) 335 } 336 return json.Marshal(&struct { 337 Removed bool `json:"removed"` 338 LogIndex string `json:"logIndex"` 339 TransactionIndex string `json:"transactionIndex"` 340 TransactionHash string `json:"transactionHash"` 341 BlockHash string `json:"blockHash"` 342 BlockNumber string `json:"blockNumber"` 343 Address string `json:"address"` 344 Data string `json:"data"` 345 Topics []string `json:"topics"` 346 }{ 347 Removed: false, 348 LogIndex: uint64ToHex(uint64(obj.log.Index)), 349 TransactionIndex: uint64ToHex(uint64(obj.log.TxIndex)), 350 TransactionHash: "0x" + hex.EncodeToString(obj.log.ActionHash[:]), 351 BlockHash: "0x" + hex.EncodeToString(obj.blockHash[:]), 352 BlockNumber: uint64ToHex(uint64(obj.log.BlockHeight)), 353 Address: addr, 354 Data: "0x" + hex.EncodeToString(obj.log.Data), 355 Topics: topics, 356 }) 357 } 358 359 func (obj *streamResponse) MarshalJSON() ([]byte, error) { 360 return json.Marshal(&struct { 361 Jsonrpc string `json:"jsonrpc"` 362 Method string `json:"method"` 363 Params streamParams `json:"params"` 364 }{ 365 Jsonrpc: "2.0", 366 Method: "eth_subscription", 367 Params: streamParams{ 368 Subscription: obj.id, 369 Result: obj.result, 370 }, 371 }) 372 }