Update types in preparation for eth internal transactions,
bump dbVersion to 6
This commit is contained in:
parent
5818ce8aa2
commit
c374ef86fd
14
api/types.go
14
api/types.go
@ -173,12 +173,14 @@ type TokenTransfer struct {
|
|||||||
|
|
||||||
// EthereumSpecific contains ethereum specific transaction data
|
// EthereumSpecific contains ethereum specific transaction data
|
||||||
type EthereumSpecific struct {
|
type EthereumSpecific struct {
|
||||||
Status eth.TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending
|
TxType string `json:"txType,omitempty"`
|
||||||
Nonce uint64 `json:"nonce"`
|
Status eth.TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending
|
||||||
GasLimit *big.Int `json:"gasLimit"`
|
Nonce uint64 `json:"nonce"`
|
||||||
GasUsed *big.Int `json:"gasUsed"`
|
GasLimit *big.Int `json:"gasLimit"`
|
||||||
GasPrice *Amount `json:"gasPrice"`
|
GasUsed *big.Int `json:"gasUsed"`
|
||||||
Data string `json:"data,omitempty"`
|
GasPrice *Amount `json:"gasPrice"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
InternalTransfers []bchain.EthereumInternalTransfer `json:"internalTransfers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx holds information about a transaction
|
// Tx holds information about a transaction
|
||||||
|
|||||||
@ -56,7 +56,7 @@ func addressFromPaddedHex(s string) (string, error) {
|
|||||||
return a.String(), nil
|
return a.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func erc20GetTransfersFromLog(logs []*rpcLog) ([]bchain.Erc20Transfer, error) {
|
func erc20GetTransfersFromLog(logs []*bchain.RpcLog) ([]bchain.Erc20Transfer, error) {
|
||||||
var r []bchain.Erc20Transfer
|
var r []bchain.Erc20Transfer
|
||||||
for _, l := range logs {
|
for _, l := range logs {
|
||||||
if len(l.Topics) == 3 && l.Topics[0] == erc20TransferEventSignature {
|
if len(l.Topics) == 3 && l.Topics[0] == erc20TransferEventSignature {
|
||||||
@ -84,7 +84,7 @@ func erc20GetTransfersFromLog(logs []*rpcLog) ([]bchain.Erc20Transfer, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func erc20GetTransfersFromTx(tx *rpcTransaction) ([]bchain.Erc20Transfer, error) {
|
func erc20GetTransfersFromTx(tx *bchain.RpcTransaction) ([]bchain.Erc20Transfer, error) {
|
||||||
var r []bchain.Erc20Transfer
|
var r []bchain.Erc20Transfer
|
||||||
if len(tx.Payload) == 128+len(erc20TransferMethodSignature) && strings.HasPrefix(tx.Payload, erc20TransferMethodSignature) {
|
if len(tx.Payload) == 128+len(erc20TransferMethodSignature) && strings.HasPrefix(tx.Payload, erc20TransferMethodSignature) {
|
||||||
to, err := addressFromPaddedHex(tx.Payload[len(erc20TransferMethodSignature) : 64+len(erc20TransferMethodSignature)])
|
to, err := addressFromPaddedHex(tx.Payload[len(erc20TransferMethodSignature) : 64+len(erc20TransferMethodSignature)])
|
||||||
|
|||||||
@ -15,13 +15,13 @@ import (
|
|||||||
func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
|
func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args []*rpcLog
|
args []*bchain.RpcLog
|
||||||
want []bchain.Erc20Transfer
|
want []bchain.Erc20Transfer
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "1",
|
name: "1",
|
||||||
args: []*rpcLog{
|
args: []*bchain.RpcLog{
|
||||||
{
|
{
|
||||||
Address: "0x76a45e8976499ab9ae223cc584019341d5a84e96",
|
Address: "0x76a45e8976499ab9ae223cc584019341d5a84e96",
|
||||||
Topics: []string{
|
Topics: []string{
|
||||||
@ -43,7 +43,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "2",
|
name: "2",
|
||||||
args: []*rpcLog{
|
args: []*bchain.RpcLog{
|
||||||
{ // Transfer
|
{ // Transfer
|
||||||
Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11",
|
Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11",
|
||||||
Topics: []string{
|
Topics: []string{
|
||||||
@ -167,17 +167,17 @@ func TestErc20_erc20GetTransfersFromTx(t *testing.T) {
|
|||||||
bn, _ := new(big.Int).SetString("21e19e0c9bab2400000", 16)
|
bn, _ := new(big.Int).SetString("21e19e0c9bab2400000", 16)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args *rpcTransaction
|
args *bchain.RpcTransaction
|
||||||
want []bchain.Erc20Transfer
|
want []bchain.Erc20Transfer
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "0",
|
name: "0",
|
||||||
args: (b.Txs[0].CoinSpecificData.(completeTransaction)).Tx,
|
args: (b.Txs[0].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
||||||
want: []bchain.Erc20Transfer{},
|
want: []bchain.Erc20Transfer{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "1",
|
name: "1",
|
||||||
args: (b.Txs[1].CoinSpecificData.(completeTransaction)).Tx,
|
args: (b.Txs[1].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
||||||
want: []bchain.Erc20Transfer{
|
want: []bchain.Erc20Transfer{
|
||||||
{
|
{
|
||||||
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
|
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
|
||||||
|
|||||||
@ -41,49 +41,13 @@ type rpcHeader struct {
|
|||||||
Nonce string `json:"nonce"`
|
Nonce string `json:"nonce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcTransaction struct {
|
|
||||||
AccountNonce string `json:"nonce"`
|
|
||||||
GasPrice string `json:"gasPrice"`
|
|
||||||
GasLimit string `json:"gas"`
|
|
||||||
To string `json:"to"` // nil means contract creation
|
|
||||||
Value string `json:"value"`
|
|
||||||
Payload string `json:"input"`
|
|
||||||
Hash string `json:"hash"`
|
|
||||||
BlockNumber string `json:"blockNumber"`
|
|
||||||
BlockHash string `json:"blockHash,omitempty"`
|
|
||||||
From string `json:"from"`
|
|
||||||
TransactionIndex string `json:"transactionIndex"`
|
|
||||||
// Signature values - ignored
|
|
||||||
// V string `json:"v"`
|
|
||||||
// R string `json:"r"`
|
|
||||||
// S string `json:"s"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type rpcLog struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
Topics []string `json:"topics"`
|
|
||||||
Data string `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type rpcLogWithTxHash struct {
|
type rpcLogWithTxHash struct {
|
||||||
rpcLog
|
bchain.RpcLog
|
||||||
Hash string `json:"transactionHash"`
|
Hash string `json:"transactionHash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcReceipt struct {
|
|
||||||
GasUsed string `json:"gasUsed"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Logs []*rpcLog `json:"logs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type completeTransaction struct {
|
|
||||||
Tx *rpcTransaction `json:"tx"`
|
|
||||||
InternalData *bchain.EthereumInternalData `json:"internalData,omitempty"`
|
|
||||||
Receipt *rpcReceipt `json:"receipt,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type rpcBlockTransactions struct {
|
type rpcBlockTransactions struct {
|
||||||
Transactions []rpcTransaction `json:"transactions"`
|
Transactions []bchain.RpcTransaction `json:"transactions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcBlockTxids struct {
|
type rpcBlockTxids struct {
|
||||||
@ -97,7 +61,7 @@ func ethNumber(n string) (int64, error) {
|
|||||||
return 0, errors.Errorf("Not a number: '%v'", n)
|
return 0, errors.Errorf("Not a number: '%v'", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, internalData *bchain.EthereumInternalData, blocktime int64, confirmations uint32, fixEIP55 bool) (*bchain.Tx, error) {
|
func (p *EthereumParser) ethTxToTx(tx *bchain.RpcTransaction, receipt *bchain.RpcReceipt, internalData *bchain.EthereumInternalData, blocktime int64, confirmations uint32, fixEIP55 bool) (*bchain.Tx, error) {
|
||||||
txid := tx.Hash
|
txid := tx.Hash
|
||||||
var (
|
var (
|
||||||
fa, ta []string
|
fa, ta []string
|
||||||
@ -136,7 +100,7 @@ func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, inte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ct := completeTransaction{
|
ct := bchain.EthereumSpecificData{
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
InternalData: internalData,
|
InternalData: internalData,
|
||||||
Receipt: receipt,
|
Receipt: receipt,
|
||||||
@ -274,7 +238,7 @@ func hexEncodeBig(b []byte) string {
|
|||||||
func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
var n uint64
|
var n uint64
|
||||||
r, ok := tx.CoinSpecificData.(completeTransaction)
|
r, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Missing CoinSpecificData")
|
return nil, errors.New("Missing CoinSpecificData")
|
||||||
}
|
}
|
||||||
@ -373,7 +337,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
rt := rpcTransaction{
|
rt := bchain.RpcTransaction{
|
||||||
AccountNonce: hexutil.EncodeUint64(pt.Tx.AccountNonce),
|
AccountNonce: hexutil.EncodeUint64(pt.Tx.AccountNonce),
|
||||||
BlockNumber: hexutil.EncodeUint64(uint64(pt.BlockNumber)),
|
BlockNumber: hexutil.EncodeUint64(uint64(pt.BlockNumber)),
|
||||||
From: EIP55Address(pt.Tx.From),
|
From: EIP55Address(pt.Tx.From),
|
||||||
@ -388,15 +352,15 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|||||||
TransactionIndex: hexutil.EncodeUint64(uint64(pt.Tx.TransactionIndex)),
|
TransactionIndex: hexutil.EncodeUint64(uint64(pt.Tx.TransactionIndex)),
|
||||||
Value: hexEncodeBig(pt.Tx.Value),
|
Value: hexEncodeBig(pt.Tx.Value),
|
||||||
}
|
}
|
||||||
var rr *rpcReceipt
|
var rr *bchain.RpcReceipt
|
||||||
if pt.Receipt != nil {
|
if pt.Receipt != nil {
|
||||||
logs := make([]*rpcLog, len(pt.Receipt.Log))
|
logs := make([]*bchain.RpcLog, len(pt.Receipt.Log))
|
||||||
for i, l := range pt.Receipt.Log {
|
for i, l := range pt.Receipt.Log {
|
||||||
topics := make([]string, len(l.Topics))
|
topics := make([]string, len(l.Topics))
|
||||||
for j, t := range l.Topics {
|
for j, t := range l.Topics {
|
||||||
topics[j] = hexutil.Encode(t)
|
topics[j] = hexutil.Encode(t)
|
||||||
}
|
}
|
||||||
logs[i] = &rpcLog{
|
logs[i] = &bchain.RpcLog{
|
||||||
Address: EIP55Address(l.Address),
|
Address: EIP55Address(l.Address),
|
||||||
Data: hexutil.Encode(l.Data),
|
Data: hexutil.Encode(l.Data),
|
||||||
Topics: topics,
|
Topics: topics,
|
||||||
@ -407,7 +371,7 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|||||||
if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' {
|
if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' {
|
||||||
status = hexEncodeBig(pt.Receipt.Status)
|
status = hexEncodeBig(pt.Receipt.Status)
|
||||||
}
|
}
|
||||||
rr = &rpcReceipt{
|
rr = &bchain.RpcReceipt{
|
||||||
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
||||||
Status: status,
|
Status: status,
|
||||||
Logs: logs,
|
Logs: logs,
|
||||||
@ -460,7 +424,7 @@ func (p *EthereumParser) GetChainType() bchain.ChainType {
|
|||||||
// GetHeightFromTx returns ethereum specific data from bchain.Tx
|
// GetHeightFromTx returns ethereum specific data from bchain.Tx
|
||||||
func GetHeightFromTx(tx *bchain.Tx) (uint32, error) {
|
func GetHeightFromTx(tx *bchain.Tx) (uint32, error) {
|
||||||
var bn string
|
var bn string
|
||||||
csd, ok := tx.CoinSpecificData.(completeTransaction)
|
csd, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, errors.New("Missing CoinSpecificData")
|
return 0, errors.New("Missing CoinSpecificData")
|
||||||
}
|
}
|
||||||
@ -476,7 +440,7 @@ func GetHeightFromTx(tx *bchain.Tx) (uint32, error) {
|
|||||||
func (p *EthereumParser) EthereumTypeGetErc20FromTx(tx *bchain.Tx) ([]bchain.Erc20Transfer, error) {
|
func (p *EthereumParser) EthereumTypeGetErc20FromTx(tx *bchain.Tx) ([]bchain.Erc20Transfer, error) {
|
||||||
var r []bchain.Erc20Transfer
|
var r []bchain.Erc20Transfer
|
||||||
var err error
|
var err error
|
||||||
csd, ok := tx.CoinSpecificData.(completeTransaction)
|
csd, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if ok {
|
if ok {
|
||||||
if csd.Receipt != nil {
|
if csd.Receipt != nil {
|
||||||
r, err = erc20GetTransfersFromLog(csd.Receipt.Logs)
|
r, err = erc20GetTransfersFromLog(csd.Receipt.Logs)
|
||||||
@ -519,7 +483,7 @@ func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
|
|||||||
// GetEthereumTxDataFromSpecificData returns EthereumTxData from coinSpecificData
|
// GetEthereumTxDataFromSpecificData returns EthereumTxData from coinSpecificData
|
||||||
func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTxData {
|
func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTxData {
|
||||||
etd := EthereumTxData{Status: TxStatusPending}
|
etd := EthereumTxData{Status: TxStatusPending}
|
||||||
csd, ok := coinSpecificData.(completeTransaction)
|
csd, ok := coinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if ok {
|
if ok {
|
||||||
if csd.Tx != nil {
|
if csd.Tx != nil {
|
||||||
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
||||||
|
|||||||
@ -89,8 +89,8 @@ func init() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CoinSpecificData: completeTransaction{
|
CoinSpecificData: bchain.EthereumSpecificData{
|
||||||
Tx: &rpcTransaction{
|
Tx: &bchain.RpcTransaction{
|
||||||
AccountNonce: "0xb26c",
|
AccountNonce: "0xb26c",
|
||||||
GasPrice: "0x430e23400",
|
GasPrice: "0x430e23400",
|
||||||
GasLimit: "0x5208",
|
GasLimit: "0x5208",
|
||||||
@ -102,10 +102,10 @@ func init() {
|
|||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
||||||
TransactionIndex: "0xa",
|
TransactionIndex: "0xa",
|
||||||
},
|
},
|
||||||
Receipt: &rpcReceipt{
|
Receipt: &bchain.RpcReceipt{
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0x5208",
|
||||||
Status: "0x1",
|
Status: "0x1",
|
||||||
Logs: []*rpcLog{},
|
Logs: []*bchain.RpcLog{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -127,8 +127,8 @@ func init() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CoinSpecificData: completeTransaction{
|
CoinSpecificData: bchain.EthereumSpecificData{
|
||||||
Tx: &rpcTransaction{
|
Tx: &bchain.RpcTransaction{
|
||||||
AccountNonce: "0xd0",
|
AccountNonce: "0xd0",
|
||||||
GasPrice: "0x9502f9000",
|
GasPrice: "0x9502f9000",
|
||||||
GasLimit: "0x130d5",
|
GasLimit: "0x130d5",
|
||||||
@ -139,10 +139,10 @@ func init() {
|
|||||||
BlockNumber: "0x41eee8",
|
BlockNumber: "0x41eee8",
|
||||||
From: "0x20cD153de35D469BA46127A0C8F18626b59a256A",
|
From: "0x20cD153de35D469BA46127A0C8F18626b59a256A",
|
||||||
TransactionIndex: "0x0"},
|
TransactionIndex: "0x0"},
|
||||||
Receipt: &rpcReceipt{
|
Receipt: &bchain.RpcReceipt{
|
||||||
GasUsed: "0xcb39",
|
GasUsed: "0xcb39",
|
||||||
Status: "0x1",
|
Status: "0x1",
|
||||||
Logs: []*rpcLog{
|
Logs: []*bchain.RpcLog{
|
||||||
{
|
{
|
||||||
Address: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
|
Address: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
|
||||||
Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000",
|
Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000",
|
||||||
@ -174,8 +174,8 @@ func init() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CoinSpecificData: completeTransaction{
|
CoinSpecificData: bchain.EthereumSpecificData{
|
||||||
Tx: &rpcTransaction{
|
Tx: &bchain.RpcTransaction{
|
||||||
AccountNonce: "0xb26c",
|
AccountNonce: "0xb26c",
|
||||||
GasPrice: "0x430e23400",
|
GasPrice: "0x430e23400",
|
||||||
GasLimit: "0x5208",
|
GasLimit: "0x5208",
|
||||||
@ -187,10 +187,10 @@ func init() {
|
|||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
||||||
TransactionIndex: "0xa",
|
TransactionIndex: "0xa",
|
||||||
},
|
},
|
||||||
Receipt: &rpcReceipt{
|
Receipt: &bchain.RpcReceipt{
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0x5208",
|
||||||
Status: "0x0",
|
Status: "0x0",
|
||||||
Logs: []*rpcLog{},
|
Logs: []*bchain.RpcLog{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -212,8 +212,8 @@ func init() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CoinSpecificData: completeTransaction{
|
CoinSpecificData: bchain.EthereumSpecificData{
|
||||||
Tx: &rpcTransaction{
|
Tx: &bchain.RpcTransaction{
|
||||||
AccountNonce: "0xb26c",
|
AccountNonce: "0xb26c",
|
||||||
GasPrice: "0x430e23400",
|
GasPrice: "0x430e23400",
|
||||||
GasLimit: "0x5208",
|
GasLimit: "0x5208",
|
||||||
@ -225,10 +225,10 @@ func init() {
|
|||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
||||||
TransactionIndex: "0xa",
|
TransactionIndex: "0xa",
|
||||||
},
|
},
|
||||||
Receipt: &rpcReceipt{
|
Receipt: &bchain.RpcReceipt{
|
||||||
GasUsed: "0x5208",
|
GasUsed: "0x5208",
|
||||||
Status: "",
|
Status: "",
|
||||||
Logs: []*rpcLog{},
|
Logs: []*bchain.RpcLog{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -351,8 +351,8 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// DeepEqual has problems with pointers in completeTransaction
|
// DeepEqual has problems with pointers in completeTransaction
|
||||||
gs := got.CoinSpecificData.(completeTransaction)
|
gs := got.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
ws := tt.want.CoinSpecificData.(completeTransaction)
|
ws := tt.want.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
gc := *got
|
gc := *got
|
||||||
wc := *tt.want
|
wc := *tt.want
|
||||||
gc.CoinSpecificData = nil
|
gc.CoinSpecificData = nil
|
||||||
|
|||||||
@ -490,7 +490,7 @@ func (b *EthereumRPC) getBlockRaw(hash string, height uint32, fullTxs bool) (jso
|
|||||||
return raw, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) getERC20EventsForBlock(blockNumber string) (map[string][]*rpcLog, error) {
|
func (b *EthereumRPC) getERC20EventsForBlock(blockNumber string) (map[string][]*bchain.RpcLog, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var logs []rpcLogWithTxHash
|
var logs []rpcLogWithTxHash
|
||||||
@ -502,10 +502,10 @@ func (b *EthereumRPC) getERC20EventsForBlock(blockNumber string) (map[string][]*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "blockNumber %v", blockNumber)
|
return nil, errors.Annotatef(err, "blockNumber %v", blockNumber)
|
||||||
}
|
}
|
||||||
r := make(map[string][]*rpcLog)
|
r := make(map[string][]*bchain.RpcLog)
|
||||||
for i := range logs {
|
for i := range logs {
|
||||||
l := &logs[i]
|
l := &logs[i]
|
||||||
r[l.Hash] = append(r[l.Hash], &l.rpcLog)
|
r[l.Hash] = append(r[l.Hash], &l.RpcLog)
|
||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
@ -555,7 +555,7 @@ func (b *EthereumRPC) processCallTrace(call rpcCallTrace, d *bchain.EthereumInte
|
|||||||
|
|
||||||
// getInternalDataForBlock fetches debug trace using callTracer, extracts internal transfers and creations and destructions of contracts
|
// getInternalDataForBlock fetches debug trace using callTracer, extracts internal transfers and creations and destructions of contracts
|
||||||
// by design, it never returns error so that missing internal transactions do not stop the rest of the blockchain import
|
// by design, it never returns error so that missing internal transactions do not stop the rest of the blockchain import
|
||||||
func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []rpcTransaction) ([]bchain.EthereumInternalData, error) {
|
func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, error) {
|
||||||
data := make([]bchain.EthereumInternalData, len(transactions))
|
data := make([]bchain.EthereumInternalData, len(transactions))
|
||||||
if b.ChainConfig.ProcessInternalTransactions {
|
if b.ChainConfig.ProcessInternalTransactions {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
@ -619,7 +619,7 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
|
|||||||
btxs := make([]bchain.Tx, len(body.Transactions))
|
btxs := make([]bchain.Tx, len(body.Transactions))
|
||||||
for i := range body.Transactions {
|
for i := range body.Transactions {
|
||||||
tx := &body.Transactions[i]
|
tx := &body.Transactions[i]
|
||||||
btx, err := b.Parser.ethTxToTx(tx, &rpcReceipt{Logs: logs[tx.Hash]}, &internalData[i], bbh.Time, uint32(bbh.Confirmations), true)
|
btx, err := b.Parser.ethTxToTx(tx, &bchain.RpcReceipt{Logs: logs[tx.Hash]}, &internalData[i], bbh.Time, uint32(bbh.Confirmations), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash)
|
return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash)
|
||||||
}
|
}
|
||||||
@ -671,7 +671,7 @@ func (b *EthereumRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error)
|
|||||||
func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var tx *rpcTransaction
|
var tx *bchain.RpcTransaction
|
||||||
hash := ethcommon.HexToHash(txid)
|
hash := ethcommon.HexToHash(txid)
|
||||||
err := b.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
err := b.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -705,7 +705,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
if time, err = ethNumber(ht.Time); err != nil {
|
if time, err = ethNumber(ht.Time); err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
var receipt rpcReceipt
|
var receipt bchain.RpcReceipt
|
||||||
err = b.rpc.CallContext(ctx, &receipt, "eth_getTransactionReceipt", hash)
|
err = b.rpc.CallContext(ctx, &receipt, "eth_getTransactionReceipt", hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
@ -733,13 +733,13 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
|
|
||||||
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
// GetTransactionSpecific returns json as returned by backend, with all coin specific data
|
||||||
func (b *EthereumRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
func (b *EthereumRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
||||||
csd, ok := tx.CoinSpecificData.(completeTransaction)
|
csd, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if !ok {
|
if !ok {
|
||||||
ntx, err := b.GetTransaction(tx.Txid)
|
ntx, err := b.GetTransaction(tx.Txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
csd, ok = ntx.CoinSpecificData.(completeTransaction)
|
csd, ok = ntx.CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Cannot get CoinSpecificData")
|
return nil, errors.New("Cannot get CoinSpecificData")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -200,49 +200,6 @@ func AddressDescriptorFromString(s string) (AddressDescriptor, error) {
|
|||||||
return nil, errors.New("invalid address descriptor")
|
return nil, errors.New("invalid address descriptor")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumType specific
|
|
||||||
|
|
||||||
// EthereumInternalTransfer contains data about internal transfer
|
|
||||||
type EthereumInternalTransfer struct {
|
|
||||||
Type EthereumInternalTransactionType `json:"type"`
|
|
||||||
From string `json:"from"`
|
|
||||||
To string `json:"to"`
|
|
||||||
Value big.Int `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// EthereumInternalTransactionType - type of ethereum transaction from internal data
|
|
||||||
type EthereumInternalTransactionType int
|
|
||||||
|
|
||||||
// EthereumInternalTransactionType enumeration
|
|
||||||
const (
|
|
||||||
CALL = EthereumInternalTransactionType(iota)
|
|
||||||
CREATE
|
|
||||||
SELFDESTRUCT
|
|
||||||
)
|
|
||||||
|
|
||||||
// EthereumInternalTransaction contains internal transfers
|
|
||||||
type EthereumInternalData struct {
|
|
||||||
Type EthereumInternalTransactionType `json:"type"`
|
|
||||||
Contract string `json:"contract,omitempty"`
|
|
||||||
Transfers []EthereumInternalTransfer `json:"transfers,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erc20Contract contains info about ERC20 contract
|
|
||||||
type Erc20Contract struct {
|
|
||||||
Contract string `json:"contract"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Symbol string `json:"symbol"`
|
|
||||||
Decimals int `json:"decimals"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erc20Transfer contains a single ERC20 token transfer
|
|
||||||
type Erc20Transfer struct {
|
|
||||||
Contract string
|
|
||||||
From string
|
|
||||||
To string
|
|
||||||
Tokens big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// MempoolTxidEntry contains mempool txid with first seen time
|
// MempoolTxidEntry contains mempool txid with first seen time
|
||||||
type MempoolTxidEntry struct {
|
type MempoolTxidEntry struct {
|
||||||
Txid string
|
Txid string
|
||||||
|
|||||||
85
bchain/types_ethereumtype.go
Normal file
85
bchain/types_ethereumtype.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package bchain
|
||||||
|
|
||||||
|
import "math/big"
|
||||||
|
|
||||||
|
// EthereumType specific
|
||||||
|
|
||||||
|
// EthereumInternalTransfer contains data about internal transfer
|
||||||
|
type EthereumInternalTransfer struct {
|
||||||
|
Type EthereumInternalTransactionType `json:"type"`
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Value big.Int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumInternalTransactionType - type of ethereum transaction from internal data
|
||||||
|
type EthereumInternalTransactionType int
|
||||||
|
|
||||||
|
// EthereumInternalTransactionType enumeration
|
||||||
|
const (
|
||||||
|
CALL = EthereumInternalTransactionType(iota)
|
||||||
|
CREATE
|
||||||
|
SELFDESTRUCT
|
||||||
|
)
|
||||||
|
|
||||||
|
// EthereumInternalTransaction contains internal transfers
|
||||||
|
type EthereumInternalData struct {
|
||||||
|
Type EthereumInternalTransactionType `json:"type"`
|
||||||
|
Contract string `json:"contract,omitempty"`
|
||||||
|
Transfers []EthereumInternalTransfer `json:"transfers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erc20Contract contains info about ERC20 contract
|
||||||
|
type Erc20Contract struct {
|
||||||
|
Contract string `json:"contract"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Symbol string `json:"symbol"`
|
||||||
|
Decimals int `json:"decimals"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erc20Transfer contains a single ERC20 token transfer
|
||||||
|
type Erc20Transfer struct {
|
||||||
|
Contract string
|
||||||
|
From string
|
||||||
|
To string
|
||||||
|
Tokens big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// RpcTransaction is returned by eth_getTransactionByHash
|
||||||
|
type RpcTransaction struct {
|
||||||
|
AccountNonce string `json:"nonce"`
|
||||||
|
GasPrice string `json:"gasPrice"`
|
||||||
|
GasLimit string `json:"gas"`
|
||||||
|
To string `json:"to"` // nil means contract creation
|
||||||
|
Value string `json:"value"`
|
||||||
|
Payload string `json:"input"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
BlockNumber string `json:"blockNumber"`
|
||||||
|
BlockHash string `json:"blockHash,omitempty"`
|
||||||
|
From string `json:"from"`
|
||||||
|
TransactionIndex string `json:"transactionIndex"`
|
||||||
|
// Signature values - ignored
|
||||||
|
// V string `json:"v"`
|
||||||
|
// R string `json:"r"`
|
||||||
|
// S string `json:"s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RpcLog is returned by eth_getLogs
|
||||||
|
type RpcLog struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Topics []string `json:"topics"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RpcLog is returned by eth_getTransactionReceipt
|
||||||
|
type RpcReceipt struct {
|
||||||
|
GasUsed string `json:"gasUsed"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Logs []*RpcLog `json:"logs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthereumSpecificData struct {
|
||||||
|
Tx *RpcTransaction `json:"tx"`
|
||||||
|
InternalData *EthereumInternalData `json:"internalData,omitempty"`
|
||||||
|
Receipt *RpcReceipt `json:"receipt,omitempty"`
|
||||||
|
}
|
||||||
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/trezor/blockbook/common"
|
"github.com/trezor/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dbVersion = 5
|
const dbVersion = 6
|
||||||
|
|
||||||
const packedHeightBytes = 4
|
const packedHeightBytes = 4
|
||||||
const maxAddrDescLen = 1024
|
const maxAddrDescLen = 1024
|
||||||
@ -112,6 +112,8 @@ const (
|
|||||||
cfTxAddresses
|
cfTxAddresses
|
||||||
// EthereumType
|
// EthereumType
|
||||||
cfAddressContracts = cfAddressBalance
|
cfAddressContracts = cfAddressBalance
|
||||||
|
cfInternalData
|
||||||
|
cfContracts
|
||||||
)
|
)
|
||||||
|
|
||||||
// common columns
|
// common columns
|
||||||
@ -120,7 +122,7 @@ var cfBaseNames = []string{"default", "height", "addresses", "blockTxs", "transa
|
|||||||
|
|
||||||
// type specific columns
|
// type specific columns
|
||||||
var cfNamesBitcoinType = []string{"addressBalance", "txAddresses"}
|
var cfNamesBitcoinType = []string{"addressBalance", "txAddresses"}
|
||||||
var cfNamesEthereumType = []string{"addressContracts"}
|
var cfNamesEthereumType = []string{"addressContracts", "internalData", "contracts"}
|
||||||
|
|
||||||
func openDB(path string, c *gorocksdb.Cache, openFiles int) (*gorocksdb.DB, []*gorocksdb.ColumnFamilyHandle, error) {
|
func openDB(path string, c *gorocksdb.Cache, openFiles int) (*gorocksdb.DB, []*gorocksdb.ColumnFamilyHandle, error) {
|
||||||
// opts with bloom filter
|
// opts with bloom filter
|
||||||
|
|||||||
@ -22,6 +22,7 @@ type AddrContract struct {
|
|||||||
type AddrContracts struct {
|
type AddrContracts struct {
|
||||||
TotalTxs uint
|
TotalTxs uint
|
||||||
NonContractTxs uint
|
NonContractTxs uint
|
||||||
|
InternalTxs uint
|
||||||
Contracts []AddrContract
|
Contracts []AddrContract
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ func (d *RocksDB) storeAddressContracts(wb *gorocksdb.WriteBatch, acm map[string
|
|||||||
varBuf := make([]byte, vlq.MaxLen64)
|
varBuf := make([]byte, vlq.MaxLen64)
|
||||||
for addrDesc, acs := range acm {
|
for addrDesc, acs := range acm {
|
||||||
// address with 0 contracts is removed from db - happens on disconnect
|
// address with 0 contracts is removed from db - happens on disconnect
|
||||||
if acs == nil || (acs.NonContractTxs == 0 && len(acs.Contracts) == 0) {
|
if acs == nil || (acs.NonContractTxs == 0 && acs.InternalTxs == 0 && len(acs.Contracts) == 0) {
|
||||||
wb.DeleteCF(d.cfh[cfAddressContracts], bchain.AddressDescriptor(addrDesc))
|
wb.DeleteCF(d.cfh[cfAddressContracts], bchain.AddressDescriptor(addrDesc))
|
||||||
} else {
|
} else {
|
||||||
buf = buf[:0]
|
buf = buf[:0]
|
||||||
@ -38,6 +39,8 @@ func (d *RocksDB) storeAddressContracts(wb *gorocksdb.WriteBatch, acm map[string
|
|||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
l = packVaruint(acs.NonContractTxs, varBuf)
|
l = packVaruint(acs.NonContractTxs, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
|
l = packVaruint(acs.InternalTxs, varBuf)
|
||||||
|
buf = append(buf, varBuf[:l]...)
|
||||||
for _, ac := range acs.Contracts {
|
for _, ac := range acs.Contracts {
|
||||||
buf = append(buf, ac.Contract...)
|
buf = append(buf, ac.Contract...)
|
||||||
l = packVaruint(ac.Txs, varBuf)
|
l = packVaruint(ac.Txs, varBuf)
|
||||||
@ -64,6 +67,8 @@ func (d *RocksDB) GetAddrDescContracts(addrDesc bchain.AddressDescriptor) (*Addr
|
|||||||
buf = buf[l:]
|
buf = buf[l:]
|
||||||
nct, l := unpackVaruint(buf)
|
nct, l := unpackVaruint(buf)
|
||||||
buf = buf[l:]
|
buf = buf[l:]
|
||||||
|
ict, l := unpackVaruint(buf)
|
||||||
|
buf = buf[l:]
|
||||||
c := make([]AddrContract, 0, 4)
|
c := make([]AddrContract, 0, 4)
|
||||||
for len(buf) > 0 {
|
for len(buf) > 0 {
|
||||||
if len(buf) < eth.EthereumTypeAddressDescriptorLen {
|
if len(buf) < eth.EthereumTypeAddressDescriptorLen {
|
||||||
@ -80,6 +85,7 @@ func (d *RocksDB) GetAddrDescContracts(addrDesc bchain.AddressDescriptor) (*Addr
|
|||||||
return &AddrContracts{
|
return &AddrContracts{
|
||||||
TotalTxs: tt,
|
TotalTxs: tt,
|
||||||
NonContractTxs: nct,
|
NonContractTxs: nct,
|
||||||
|
InternalTxs: ict,
|
||||||
Contracts: c,
|
Contracts: c,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,10 +44,10 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "010100", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0201" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010100", nil},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
{
|
{
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -113,14 +113,14 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "010100", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0402" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "040200" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010100", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010100", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "0100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "0101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "010100", nil},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
{
|
{
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@ -84,9 +84,9 @@ Column families used only by **Ethereum type** coins:
|
|||||||
|
|
||||||
- **addressContracts** (used only by Ethereum type coins)
|
- **addressContracts** (used only by Ethereum type coins)
|
||||||
|
|
||||||
Maps *addrDesc* to *total number of transactions*, *number of non contract transactions* and array of *contracts* with *number of transfers* of given address.
|
Maps *addrDesc* to *total number of transactions*, *number of non contract transactions*, *number of internal transactions* and array of *contracts* with *number of transfers* of given address.
|
||||||
```
|
```
|
||||||
(addrDesc []byte) -> (total_txs vuint)+(non-contract_txs vuint)+[]((contractAddrDesc []byte)+(nr_transfers vuint))
|
(addrDesc []byte) -> (total_txs vuint)+(non-contract_txs vuint)+(internal_txs vuint)+[]((contractAddrDesc []byte)+(nr_transfers vuint))
|
||||||
```
|
```
|
||||||
|
|
||||||
- **blockTxs**
|
- **blockTxs**
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user