463 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			463 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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.UncleHash())
 | |
| 	res.LogsBloom = newHexData(block.Bloom())
 | |
| 	res.TransactionRoot = newHexData(block.TxHash())
 | |
| 	res.StateRoot = newHexData(block.Root())
 | |
| 	res.Miner = newHexData(block.Coinbase())
 | |
| 	res.Difficulty = newHexNum(block.Difficulty())
 | |
| 	res.TotalDifficulty = newHexNum(block.Td)
 | |
| 	res.Size = newHexNum(block.Size().Int64())
 | |
| 	res.ExtraData = newHexData(block.Extra())
 | |
| 	res.GasLimit = newHexNum(block.GasLimit())
 | |
| 	res.GasUsed = newHexNum(block.GasUsed())
 | |
| 	res.UnixTimestamp = newHexNum(block.Time())
 | |
| 
 | |
| 	txs := block.Transactions()
 | |
| 	res.Transactions = make([]*TransactionRes, len(txs))
 | |
| 	for i, tx := range txs {
 | |
| 		res.Transactions[i] = NewTransactionRes(tx)
 | |
| 		res.Transactions[i].BlockHash = res.BlockHash
 | |
| 		res.Transactions[i].BlockNumber = res.BlockNumber
 | |
| 		res.Transactions[i].TxIndex = newHexNum(i)
 | |
| 	}
 | |
| 
 | |
| 	uncles := block.Uncles()
 | |
| 	res.Uncles = make([]*UncleRes, len(uncles))
 | |
| 	for i, uncle := range 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)
 | |
| }
 |