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  }