github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/bchain/coins/eth/ethparser.go (about)

     1  package eth
     2  
     3  import (
     4  	"blockbook/bchain"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"math/big"
     8  	"strconv"
     9  
    10  	"github.com/ethereum/go-ethereum/common/hexutil"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/juju/errors"
    14  
    15  	ethcommon "github.com/ethereum/go-ethereum/common"
    16  )
    17  
    18  // EthereumParser handle
    19  type EthereumParser struct {
    20  	*bchain.BaseParser
    21  }
    22  
    23  // NewEthereumParser returns new EthereumParser instance
    24  func NewEthereumParser() *EthereumParser {
    25  	return &EthereumParser{&bchain.BaseParser{
    26  		BlockAddressesToKeep: 0,
    27  		AmountDecimalPoint:   18,
    28  	}}
    29  }
    30  
    31  type rpcTransaction struct {
    32  	AccountNonce     string          `json:"nonce"    gencodec:"required"`
    33  	Price            string          `json:"gasPrice" gencodec:"required"`
    34  	GasLimit         string          `json:"gas"      gencodec:"required"`
    35  	To               string          `json:"to"       rlp:"nil"` // nil means contract creation
    36  	Value            string          `json:"value"    gencodec:"required"`
    37  	Payload          string          `json:"input"    gencodec:"required"`
    38  	Hash             ethcommon.Hash  `json:"hash" rlp:"-"`
    39  	BlockNumber      string          `json:"blockNumber"`
    40  	BlockHash        *ethcommon.Hash `json:"blockHash,omitempty"`
    41  	From             string          `json:"from"`
    42  	TransactionIndex string          `json:"transactionIndex"`
    43  	// Signature values
    44  	V string `json:"v" gencodec:"required"`
    45  	R string `json:"r" gencodec:"required"`
    46  	S string `json:"s" gencodec:"required"`
    47  }
    48  
    49  type rpcBlock struct {
    50  	Hash         ethcommon.Hash   `json:"hash"`
    51  	Transactions []rpcTransaction `json:"transactions"`
    52  	UncleHashes  []ethcommon.Hash `json:"uncles"`
    53  }
    54  
    55  func ethHashToHash(h ethcommon.Hash) string {
    56  	return h.Hex()
    57  }
    58  
    59  func ethNumber(n string) (int64, error) {
    60  	if len(n) > 2 {
    61  		return strconv.ParseInt(n[2:], 16, 64)
    62  	}
    63  	return 0, errors.Errorf("Not a number: '%v'", n)
    64  }
    65  
    66  func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, blocktime int64, confirmations uint32) (*bchain.Tx, error) {
    67  	txid := ethHashToHash(tx.Hash)
    68  	var (
    69  		fa, ta []string
    70  		err    error
    71  	)
    72  	if len(tx.From) > 2 {
    73  		fa = []string{tx.From}
    74  	}
    75  	if len(tx.To) > 2 {
    76  		ta = []string{tx.To}
    77  	}
    78  	// temporarily, the complete rpcTransaction without BlockHash is marshalled and hex encoded to bchain.Tx.Hex
    79  	bh := tx.BlockHash
    80  	tx.BlockHash = nil
    81  	b, err := json.Marshal(tx)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	tx.BlockHash = bh
    86  	h := hex.EncodeToString(b)
    87  	vs, err := hexutil.DecodeBig(tx.Value)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return &bchain.Tx{
    92  		Blocktime:     blocktime,
    93  		Confirmations: confirmations,
    94  		Hex:           h,
    95  		// LockTime
    96  		Time: blocktime,
    97  		Txid: txid,
    98  		Vin: []bchain.Vin{
    99  			{
   100  				Addresses: fa,
   101  				// Coinbase
   102  				// ScriptSig
   103  				// Sequence
   104  				// Txid
   105  				// Vout
   106  			},
   107  		},
   108  		Vout: []bchain.Vout{
   109  			{
   110  				N:        0, // there is always up to one To address
   111  				ValueSat: *vs,
   112  				ScriptPubKey: bchain.ScriptPubKey{
   113  					// Hex
   114  					Addresses: ta,
   115  				},
   116  			},
   117  		},
   118  	}, nil
   119  }
   120  
   121  // GetAddrDescFromVout returns internal address representation of given transaction output
   122  func (p *EthereumParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) {
   123  	if len(output.ScriptPubKey.Addresses) != 1 {
   124  		return nil, bchain.ErrAddressMissing
   125  	}
   126  	return p.GetAddrDescFromAddress(output.ScriptPubKey.Addresses[0])
   127  }
   128  
   129  func has0xPrefix(s string) bool {
   130  	return len(s) >= 2 && s[0] == '0' && (s[1]|32) == 'x'
   131  }
   132  
   133  // GetAddrDescFromAddress returns internal address representation of given address
   134  func (p *EthereumParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) {
   135  	// github.com/ethereum/go-ethereum/common.HexToAddress does not handle address errors, using own decoding
   136  	if has0xPrefix(address) {
   137  		address = address[2:]
   138  	}
   139  	if len(address) == 0 {
   140  		return nil, bchain.ErrAddressMissing
   141  	}
   142  	if len(address)&1 == 1 {
   143  		address = "0" + address
   144  	}
   145  	return hex.DecodeString(address)
   146  }
   147  
   148  // GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable
   149  func (p *EthereumParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
   150  	return []string{hexutil.Encode(addrDesc)}, true, nil
   151  }
   152  
   153  // GetScriptFromAddrDesc returns output script for given address descriptor
   154  func (p *EthereumParser) GetScriptFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]byte, error) {
   155  	return addrDesc, nil
   156  }
   157  
   158  func hexDecode(s string) ([]byte, error) {
   159  	b, err := hexutil.Decode(s)
   160  	if err != nil && err != hexutil.ErrEmptyString {
   161  		return nil, err
   162  	}
   163  	return b, nil
   164  }
   165  
   166  func hexDecodeBig(s string) ([]byte, error) {
   167  	b, err := hexutil.DecodeBig(s)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	return b.Bytes(), nil
   172  }
   173  
   174  func hexEncodeBig(b []byte) string {
   175  	var i big.Int
   176  	i.SetBytes(b)
   177  	return hexutil.EncodeBig(&i)
   178  }
   179  
   180  // PackTx packs transaction to byte array
   181  func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
   182  	b, err := hex.DecodeString(tx.Hex)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	var r rpcTransaction
   187  	var n uint64
   188  	err = json.Unmarshal(b, &r)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	pt := &ProtoTransaction{}
   193  	if pt.AccountNonce, err = hexutil.DecodeUint64(r.AccountNonce); err != nil {
   194  		return nil, errors.Annotatef(err, "AccountNonce %v", r.AccountNonce)
   195  	}
   196  	if n, err = hexutil.DecodeUint64(r.BlockNumber); err != nil {
   197  		return nil, errors.Annotatef(err, "BlockNumber %v", r.BlockNumber)
   198  	}
   199  	pt.BlockNumber = uint32(n)
   200  	pt.BlockTime = uint64(blockTime)
   201  	if pt.From, err = hexDecode(r.From); err != nil {
   202  		return nil, errors.Annotatef(err, "From %v", r.From)
   203  	}
   204  	if pt.GasLimit, err = hexutil.DecodeUint64(r.GasLimit); err != nil {
   205  		return nil, errors.Annotatef(err, "GasLimit %v", r.GasLimit)
   206  	}
   207  	pt.Hash = r.Hash.Bytes()
   208  	if pt.Payload, err = hexDecode(r.Payload); err != nil {
   209  		return nil, errors.Annotatef(err, "Payload %v", r.Payload)
   210  	}
   211  	if pt.Price, err = hexDecodeBig(r.Price); err != nil {
   212  		return nil, errors.Annotatef(err, "Price %v", r.Price)
   213  	}
   214  	if pt.R, err = hexDecodeBig(r.R); err != nil {
   215  		return nil, errors.Annotatef(err, "R %v", r.R)
   216  	}
   217  	if pt.S, err = hexDecodeBig(r.S); err != nil {
   218  		return nil, errors.Annotatef(err, "S %v", r.S)
   219  	}
   220  	if pt.V, err = hexDecodeBig(r.V); err != nil {
   221  		return nil, errors.Annotatef(err, "V %v", r.V)
   222  	}
   223  	if pt.To, err = hexDecode(r.To); err != nil {
   224  		return nil, errors.Annotatef(err, "To %v", r.To)
   225  	}
   226  	if n, err = hexutil.DecodeUint64(r.TransactionIndex); err != nil {
   227  		return nil, errors.Annotatef(err, "TransactionIndex %v", r.TransactionIndex)
   228  	}
   229  	pt.TransactionIndex = uint32(n)
   230  	if pt.Value, err = hexDecodeBig(r.Value); err != nil {
   231  		return nil, errors.Annotatef(err, "Value %v", r.Value)
   232  	}
   233  	return proto.Marshal(pt)
   234  }
   235  
   236  // UnpackTx unpacks transaction from byte array
   237  func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
   238  	var pt ProtoTransaction
   239  	err := proto.Unmarshal(buf, &pt)
   240  	if err != nil {
   241  		return nil, 0, err
   242  	}
   243  	r := rpcTransaction{
   244  		AccountNonce:     hexutil.EncodeUint64(pt.AccountNonce),
   245  		BlockNumber:      hexutil.EncodeUint64(uint64(pt.BlockNumber)),
   246  		From:             hexutil.Encode(pt.From),
   247  		GasLimit:         hexutil.EncodeUint64(pt.GasLimit),
   248  		Hash:             ethcommon.BytesToHash(pt.Hash),
   249  		Payload:          hexutil.Encode(pt.Payload),
   250  		Price:            hexEncodeBig(pt.Price),
   251  		R:                hexEncodeBig(pt.R),
   252  		S:                hexEncodeBig(pt.S),
   253  		V:                hexEncodeBig(pt.V),
   254  		To:               hexutil.Encode(pt.To),
   255  		TransactionIndex: hexutil.EncodeUint64(uint64(pt.TransactionIndex)),
   256  		Value:            hexEncodeBig(pt.Value),
   257  	}
   258  	tx, err := p.ethTxToTx(&r, int64(pt.BlockTime), 0)
   259  	if err != nil {
   260  		return nil, 0, err
   261  	}
   262  	return tx, pt.BlockNumber, nil
   263  }
   264  
   265  // PackedTxidLen returns length in bytes of packed txid
   266  func (p *EthereumParser) PackedTxidLen() int {
   267  	return 32
   268  }
   269  
   270  // PackTxid packs txid to byte array
   271  func (p *EthereumParser) PackTxid(txid string) ([]byte, error) {
   272  	if has0xPrefix(txid) {
   273  		txid = txid[2:]
   274  	}
   275  	return hex.DecodeString(txid)
   276  }
   277  
   278  // UnpackTxid unpacks byte array to txid
   279  func (p *EthereumParser) UnpackTxid(buf []byte) (string, error) {
   280  	return hexutil.Encode(buf), nil
   281  }
   282  
   283  // PackBlockHash packs block hash to byte array
   284  func (p *EthereumParser) PackBlockHash(hash string) ([]byte, error) {
   285  	if has0xPrefix(hash) {
   286  		hash = hash[2:]
   287  	}
   288  	return hex.DecodeString(hash)
   289  }
   290  
   291  // UnpackBlockHash unpacks byte array to block hash
   292  func (p *EthereumParser) UnpackBlockHash(buf []byte) (string, error) {
   293  	return hexutil.Encode(buf), nil
   294  }
   295  
   296  // IsUTXOChain returns true if the block chain is UTXO type, otherwise false
   297  func (p *EthereumParser) IsUTXOChain() bool {
   298  	return false
   299  }