aboutsummaryrefslogtreecommitdiffstats
path: root/rpc/api/parsing.go
diff options
context:
space:
mode:
Diffstat (limited to 'rpc/api/parsing.go')
-rw-r--r--rpc/api/parsing.go460
1 files changed, 460 insertions, 0 deletions
diff --git a/rpc/api/parsing.go b/rpc/api/parsing.go
new file mode 100644
index 000000000..85a9165e5
--- /dev/null
+++ b/rpc/api/parsing.go
@@ -0,0 +1,460 @@
+package api
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/json"
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rpc/shared"
+)
+
+type hexdata struct {
+ data []byte
+ isNil bool
+}
+
+func (d *hexdata) String() string {
+ return "0x" + common.Bytes2Hex(d.data)
+}
+
+func (d *hexdata) MarshalJSON() ([]byte, error) {
+ if d.isNil {
+ return json.Marshal(nil)
+ }
+ return json.Marshal(d.String())
+}
+
+func newHexData(input interface{}) *hexdata {
+ d := new(hexdata)
+
+ if input == nil {
+ d.isNil = true
+ return d
+ }
+ switch input := input.(type) {
+ case []byte:
+ d.data = input
+ case common.Hash:
+ d.data = input.Bytes()
+ case *common.Hash:
+ if input == nil {
+ d.isNil = true
+ } else {
+ d.data = input.Bytes()
+ }
+ case common.Address:
+ d.data = input.Bytes()
+ case *common.Address:
+ if input == nil {
+ d.isNil = true
+ } else {
+ d.data = input.Bytes()
+ }
+ case types.Bloom:
+ d.data = input.Bytes()
+ case *types.Bloom:
+ if input == nil {
+ d.isNil = true
+ } else {
+ d.data = input.Bytes()
+ }
+ case *big.Int:
+ if input == nil {
+ d.isNil = true
+ } else {
+ d.data = input.Bytes()
+ }
+ case int64:
+ d.data = big.NewInt(input).Bytes()
+ case uint64:
+ buff := make([]byte, 8)
+ binary.BigEndian.PutUint64(buff, input)
+ d.data = buff
+ case int:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case uint:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case int8:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case uint8:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case int16:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case uint16:
+ buff := make([]byte, 2)
+ binary.BigEndian.PutUint16(buff, input)
+ d.data = buff
+ case int32:
+ d.data = big.NewInt(int64(input)).Bytes()
+ case uint32:
+ buff := make([]byte, 4)
+ binary.BigEndian.PutUint32(buff, input)
+ d.data = buff
+ case string: // hexstring
+ // aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded
+ bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
+ if err != nil {
+ d.isNil = true
+ } else {
+ d.data = bytes
+ }
+ default:
+ d.isNil = true
+ }
+
+ return d
+}
+
+type hexnum struct {
+ data []byte
+ isNil bool
+}
+
+func (d *hexnum) String() string {
+ // Get hex string from bytes
+ out := common.Bytes2Hex(d.data)
+ // Trim leading 0s
+ out = strings.TrimLeft(out, "0")
+ // Output "0x0" when value is 0
+ if len(out) == 0 {
+ out = "0"
+ }
+ return "0x" + out
+}
+
+func (d *hexnum) MarshalJSON() ([]byte, error) {
+ if d.isNil {
+ return json.Marshal(nil)
+ }
+ return json.Marshal(d.String())
+}
+
+func newHexNum(input interface{}) *hexnum {
+ d := new(hexnum)
+
+ d.data = newHexData(input).data
+
+ return d
+}
+
+type BlockRes struct {
+ fullTx bool
+
+ BlockNumber *hexnum `json:"number"`
+ BlockHash *hexdata `json:"hash"`
+ ParentHash *hexdata `json:"parentHash"`
+ Nonce *hexdata `json:"nonce"`
+ Sha3Uncles *hexdata `json:"sha3Uncles"`
+ LogsBloom *hexdata `json:"logsBloom"`
+ TransactionRoot *hexdata `json:"transactionsRoot"`
+ StateRoot *hexdata `json:"stateRoot"`
+ Miner *hexdata `json:"miner"`
+ Difficulty *hexnum `json:"difficulty"`
+ TotalDifficulty *hexnum `json:"totalDifficulty"`
+ Size *hexnum `json:"size"`
+ ExtraData *hexdata `json:"extraData"`
+ GasLimit *hexnum `json:"gasLimit"`
+ GasUsed *hexnum `json:"gasUsed"`
+ UnixTimestamp *hexnum `json:"timestamp"`
+ Transactions []*TransactionRes `json:"transactions"`
+ Uncles []*UncleRes `json:"uncles"`
+}
+
+func (b *BlockRes) MarshalJSON() ([]byte, error) {
+ if b.fullTx {
+ var ext struct {
+ BlockNumber *hexnum `json:"number"`
+ BlockHash *hexdata `json:"hash"`
+ ParentHash *hexdata `json:"parentHash"`
+ Nonce *hexdata `json:"nonce"`
+ Sha3Uncles *hexdata `json:"sha3Uncles"`
+ LogsBloom *hexdata `json:"logsBloom"`
+ TransactionRoot *hexdata `json:"transactionsRoot"`
+ StateRoot *hexdata `json:"stateRoot"`
+ Miner *hexdata `json:"miner"`
+ Difficulty *hexnum `json:"difficulty"`
+ TotalDifficulty *hexnum `json:"totalDifficulty"`
+ Size *hexnum `json:"size"`
+ ExtraData *hexdata `json:"extraData"`
+ GasLimit *hexnum `json:"gasLimit"`
+ GasUsed *hexnum `json:"gasUsed"`
+ UnixTimestamp *hexnum `json:"timestamp"`
+ Transactions []*TransactionRes `json:"transactions"`
+ Uncles []*hexdata `json:"uncles"`
+ }
+
+ ext.BlockNumber = b.BlockNumber
+ ext.BlockHash = b.BlockHash
+ ext.ParentHash = b.ParentHash
+ ext.Nonce = b.Nonce
+ ext.Sha3Uncles = b.Sha3Uncles
+ ext.LogsBloom = b.LogsBloom
+ ext.TransactionRoot = b.TransactionRoot
+ ext.StateRoot = b.StateRoot
+ ext.Miner = b.Miner
+ ext.Difficulty = b.Difficulty
+ ext.TotalDifficulty = b.TotalDifficulty
+ ext.Size = b.Size
+ ext.ExtraData = b.ExtraData
+ ext.GasLimit = b.GasLimit
+ ext.GasUsed = b.GasUsed
+ ext.UnixTimestamp = b.UnixTimestamp
+ ext.Transactions = b.Transactions
+ ext.Uncles = make([]*hexdata, len(b.Uncles))
+ for i, u := range b.Uncles {
+ ext.Uncles[i] = u.BlockHash
+ }
+ return json.Marshal(ext)
+ } else {
+ var ext struct {
+ BlockNumber *hexnum `json:"number"`
+ BlockHash *hexdata `json:"hash"`
+ ParentHash *hexdata `json:"parentHash"`
+ Nonce *hexdata `json:"nonce"`
+ Sha3Uncles *hexdata `json:"sha3Uncles"`
+ LogsBloom *hexdata `json:"logsBloom"`
+ TransactionRoot *hexdata `json:"transactionsRoot"`
+ StateRoot *hexdata `json:"stateRoot"`
+ Miner *hexdata `json:"miner"`
+ Difficulty *hexnum `json:"difficulty"`
+ TotalDifficulty *hexnum `json:"totalDifficulty"`
+ Size *hexnum `json:"size"`
+ ExtraData *hexdata `json:"extraData"`
+ GasLimit *hexnum `json:"gasLimit"`
+ GasUsed *hexnum `json:"gasUsed"`
+ UnixTimestamp *hexnum `json:"timestamp"`
+ Transactions []*hexdata `json:"transactions"`
+ Uncles []*hexdata `json:"uncles"`
+ }
+
+ ext.BlockNumber = b.BlockNumber
+ ext.BlockHash = b.BlockHash
+ ext.ParentHash = b.ParentHash
+ ext.Nonce = b.Nonce
+ ext.Sha3Uncles = b.Sha3Uncles
+ ext.LogsBloom = b.LogsBloom
+ ext.TransactionRoot = b.TransactionRoot
+ ext.StateRoot = b.StateRoot
+ ext.Miner = b.Miner
+ ext.Difficulty = b.Difficulty
+ ext.TotalDifficulty = b.TotalDifficulty
+ ext.Size = b.Size
+ ext.ExtraData = b.ExtraData
+ ext.GasLimit = b.GasLimit
+ ext.GasUsed = b.GasUsed
+ ext.UnixTimestamp = b.UnixTimestamp
+ ext.Transactions = make([]*hexdata, len(b.Transactions))
+ for i, tx := range b.Transactions {
+ ext.Transactions[i] = tx.Hash
+ }
+ ext.Uncles = make([]*hexdata, len(b.Uncles))
+ for i, u := range b.Uncles {
+ ext.Uncles[i] = u.BlockHash
+ }
+ return json.Marshal(ext)
+ }
+}
+
+func NewBlockRes(block *types.Block, fullTx bool) *BlockRes {
+ if block == nil {
+ return nil
+ }
+
+ res := new(BlockRes)
+ res.fullTx = fullTx
+ res.BlockNumber = newHexNum(block.Number())
+ res.BlockHash = newHexData(block.Hash())
+ res.ParentHash = newHexData(block.ParentHash())
+ res.Nonce = newHexData(block.Nonce())
+ res.Sha3Uncles = newHexData(block.Header().UncleHash)
+ res.LogsBloom = newHexData(block.Bloom())
+ res.TransactionRoot = newHexData(block.Header().TxHash)
+ res.StateRoot = newHexData(block.Root())
+ res.Miner = newHexData(block.Header().Coinbase)
+ res.Difficulty = newHexNum(block.Difficulty())
+ res.TotalDifficulty = newHexNum(block.Td)
+ res.Size = newHexNum(block.Size().Int64())
+ res.ExtraData = newHexData(block.Header().Extra)
+ res.GasLimit = newHexNum(block.GasLimit())
+ res.GasUsed = newHexNum(block.GasUsed())
+ res.UnixTimestamp = newHexNum(block.Time())
+
+ res.Transactions = make([]*TransactionRes, len(block.Transactions()))
+ for i, tx := range block.Transactions() {
+ res.Transactions[i] = NewTransactionRes(tx)
+ res.Transactions[i].BlockHash = res.BlockHash
+ res.Transactions[i].BlockNumber = res.BlockNumber
+ res.Transactions[i].TxIndex = newHexNum(i)
+ }
+
+ res.Uncles = make([]*UncleRes, len(block.Uncles()))
+ for i, uncle := range block.Uncles() {
+ res.Uncles[i] = NewUncleRes(uncle)
+ }
+
+ return res
+}
+
+type TransactionRes struct {
+ Hash *hexdata `json:"hash"`
+ Nonce *hexnum `json:"nonce"`
+ BlockHash *hexdata `json:"blockHash"`
+ BlockNumber *hexnum `json:"blockNumber"`
+ TxIndex *hexnum `json:"transactionIndex"`
+ From *hexdata `json:"from"`
+ To *hexdata `json:"to"`
+ Value *hexnum `json:"value"`
+ Gas *hexnum `json:"gas"`
+ GasPrice *hexnum `json:"gasPrice"`
+ Input *hexdata `json:"input"`
+}
+
+func NewTransactionRes(tx *types.Transaction) *TransactionRes {
+ if tx == nil {
+ return nil
+ }
+
+ var v = new(TransactionRes)
+ v.Hash = newHexData(tx.Hash())
+ v.Nonce = newHexNum(tx.Nonce())
+ // v.BlockHash =
+ // v.BlockNumber =
+ // v.TxIndex =
+ from, _ := tx.From()
+ v.From = newHexData(from)
+ v.To = newHexData(tx.To())
+ v.Value = newHexNum(tx.Value())
+ v.Gas = newHexNum(tx.Gas())
+ v.GasPrice = newHexNum(tx.GasPrice())
+ v.Input = newHexData(tx.Data())
+ return v
+}
+
+type UncleRes struct {
+ BlockNumber *hexnum `json:"number"`
+ BlockHash *hexdata `json:"hash"`
+ ParentHash *hexdata `json:"parentHash"`
+ Nonce *hexdata `json:"nonce"`
+ Sha3Uncles *hexdata `json:"sha3Uncles"`
+ ReceiptHash *hexdata `json:"receiptHash"`
+ LogsBloom *hexdata `json:"logsBloom"`
+ TransactionRoot *hexdata `json:"transactionsRoot"`
+ StateRoot *hexdata `json:"stateRoot"`
+ Miner *hexdata `json:"miner"`
+ Difficulty *hexnum `json:"difficulty"`
+ ExtraData *hexdata `json:"extraData"`
+ GasLimit *hexnum `json:"gasLimit"`
+ GasUsed *hexnum `json:"gasUsed"`
+ UnixTimestamp *hexnum `json:"timestamp"`
+}
+
+func NewUncleRes(h *types.Header) *UncleRes {
+ if h == nil {
+ return nil
+ }
+
+ var v = new(UncleRes)
+ v.BlockNumber = newHexNum(h.Number)
+ v.BlockHash = newHexData(h.Hash())
+ v.ParentHash = newHexData(h.ParentHash)
+ v.Sha3Uncles = newHexData(h.UncleHash)
+ v.Nonce = newHexData(h.Nonce[:])
+ v.LogsBloom = newHexData(h.Bloom)
+ v.TransactionRoot = newHexData(h.TxHash)
+ v.StateRoot = newHexData(h.Root)
+ v.Miner = newHexData(h.Coinbase)
+ v.Difficulty = newHexNum(h.Difficulty)
+ v.ExtraData = newHexData(h.Extra)
+ v.GasLimit = newHexNum(h.GasLimit)
+ v.GasUsed = newHexNum(h.GasUsed)
+ v.UnixTimestamp = newHexNum(h.Time)
+ v.ReceiptHash = newHexData(h.ReceiptHash)
+
+ return v
+}
+
+// type FilterLogRes struct {
+// Hash string `json:"hash"`
+// Address string `json:"address"`
+// Data string `json:"data"`
+// BlockNumber string `json:"blockNumber"`
+// TransactionHash string `json:"transactionHash"`
+// BlockHash string `json:"blockHash"`
+// TransactionIndex string `json:"transactionIndex"`
+// LogIndex string `json:"logIndex"`
+// }
+
+// type FilterWhisperRes struct {
+// Hash string `json:"hash"`
+// From string `json:"from"`
+// To string `json:"to"`
+// Expiry string `json:"expiry"`
+// Sent string `json:"sent"`
+// Ttl string `json:"ttl"`
+// Topics string `json:"topics"`
+// Payload string `json:"payload"`
+// WorkProved string `json:"workProved"`
+// }
+
+func numString(raw interface{}) (*big.Int, error) {
+ var number *big.Int
+ // Parse as integer
+ num, ok := raw.(float64)
+ if ok {
+ number = big.NewInt(int64(num))
+ return number, nil
+ }
+
+ // Parse as string/hexstring
+ str, ok := raw.(string)
+ if ok {
+ number = common.String2Big(str)
+ return number, nil
+ }
+
+ return nil, shared.NewInvalidTypeError("", "not a number or string")
+}
+
+func blockHeight(raw interface{}, number *int64) error {
+ // Parse as integer
+ num, ok := raw.(float64)
+ if ok {
+ *number = int64(num)
+ return nil
+ }
+
+ // Parse as string/hexstring
+ str, ok := raw.(string)
+ if !ok {
+ return shared.NewInvalidTypeError("", "not a number or string")
+ }
+
+ switch str {
+ case "earliest":
+ *number = 0
+ case "latest":
+ *number = -1
+ case "pending":
+ *number = -2
+ default:
+ if common.HasHexPrefix(str) {
+ *number = common.String2Big(str).Int64()
+ } else {
+ return shared.NewInvalidTypeError("blockNumber", "is not a valid string")
+ }
+ }
+
+ return nil
+}
+
+func blockHeightFromJson(msg json.RawMessage, number *int64) error {
+ var raw interface{}
+ if err := json.Unmarshal(msg, &raw); err != nil {
+ return shared.NewDecodeParamError(err.Error())
+ }
+ return blockHeight(raw, number)
+}