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 }