Store contract info in DB
This commit is contained in:
parent
2507e12057
commit
db91824dc3
98
api/types.go
98
api/types.go
@ -135,58 +135,40 @@ type Vout struct {
|
|||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenType specifies type of token
|
// MultiTokenValue contains values for contract with id and value (like ERC1155)
|
||||||
type TokenType string
|
type MultiTokenValue struct {
|
||||||
|
|
||||||
// Token types
|
|
||||||
const (
|
|
||||||
// Ethereum token types
|
|
||||||
ERC20TokenType TokenType = "ERC20"
|
|
||||||
ERC771TokenType TokenType = "ERC721"
|
|
||||||
ERC1155TokenType TokenType = "ERC1155"
|
|
||||||
|
|
||||||
// XPUBAddressTokenType is address derived from xpub
|
|
||||||
XPUBAddressTokenType TokenType = "XPUBAddress"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TokenTypeMap maps bchain.TokenTransferType to TokenType
|
|
||||||
// the map must match all bchain.TokenTransferTypes to avoid index out of range panic
|
|
||||||
var TokenTypeMap []TokenType = []TokenType{ERC20TokenType, ERC771TokenType, ERC1155TokenType}
|
|
||||||
|
|
||||||
// TokenTransferValues contains values for ERC1155 contract
|
|
||||||
type TokenTransferValues struct {
|
|
||||||
Id *Amount `json:"id,omitempty"`
|
Id *Amount `json:"id,omitempty"`
|
||||||
Value *Amount `json:"value,omitempty"`
|
Value *Amount `json:"value,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token contains info about tokens held by an address
|
// Token contains info about tokens held by an address
|
||||||
type Token struct {
|
type Token struct {
|
||||||
Type TokenType `json:"type"`
|
Type bchain.TokenTypeName `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Contract string `json:"contract,omitempty"`
|
Contract string `json:"contract,omitempty"`
|
||||||
Transfers int `json:"transfers"`
|
Transfers int `json:"transfers"`
|
||||||
Symbol string `json:"symbol,omitempty"`
|
Symbol string `json:"symbol,omitempty"`
|
||||||
Decimals int `json:"decimals,omitempty"`
|
Decimals int `json:"decimals,omitempty"`
|
||||||
BalanceSat *Amount `json:"balance,omitempty"`
|
BalanceSat *Amount `json:"balance,omitempty"`
|
||||||
Ids []Amount `json:"ids,omitempty"` // multiple ERC721 tokens
|
Ids []Amount `json:"ids,omitempty"` // multiple ERC721 tokens
|
||||||
IdValues []TokenTransferValues `json:"idValues,omitempty"` // multiple ERC1155 tokens
|
MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"` // multiple ERC1155 tokens
|
||||||
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
|
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
|
||||||
TotalSentSat *Amount `json:"totalSent,omitempty"`
|
TotalSentSat *Amount `json:"totalSent,omitempty"`
|
||||||
ContractIndex string `json:"-"`
|
ContractIndex string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenTransfer contains info about a token transfer done in a transaction
|
// TokenTransfer contains info about a token transfer done in a transaction
|
||||||
type TokenTransfer struct {
|
type TokenTransfer struct {
|
||||||
Type TokenType `json:"type"`
|
Type bchain.TokenTypeName `json:"type"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Decimals int `json:"decimals"`
|
Decimals int `json:"decimals"`
|
||||||
Value *Amount `json:"value,omitempty"`
|
Value *Amount `json:"value,omitempty"`
|
||||||
Values []TokenTransferValues `json:"values,omitempty"`
|
MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EthereumInternalTransfer struct {
|
type EthereumInternalTransfer struct {
|
||||||
@ -290,22 +272,22 @@ type AddressFilter struct {
|
|||||||
// Address holds information about address and its transactions
|
// Address holds information about address and its transactions
|
||||||
type Address struct {
|
type Address struct {
|
||||||
Paging
|
Paging
|
||||||
AddrStr string `json:"address"`
|
AddrStr string `json:"address"`
|
||||||
BalanceSat *Amount `json:"balance"`
|
BalanceSat *Amount `json:"balance"`
|
||||||
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
|
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
|
||||||
TotalSentSat *Amount `json:"totalSent,omitempty"`
|
TotalSentSat *Amount `json:"totalSent,omitempty"`
|
||||||
UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
|
UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
|
||||||
UnconfirmedTxs int `json:"unconfirmedTxs"`
|
UnconfirmedTxs int `json:"unconfirmedTxs"`
|
||||||
Txs int `json:"txs"`
|
Txs int `json:"txs"`
|
||||||
NonTokenTxs int `json:"nonTokenTxs,omitempty"`
|
NonTokenTxs int `json:"nonTokenTxs,omitempty"`
|
||||||
InternalTxs int `json:"internalTxs,omitempty"`
|
InternalTxs int `json:"internalTxs,omitempty"`
|
||||||
Transactions []*Tx `json:"transactions,omitempty"`
|
Transactions []*Tx `json:"transactions,omitempty"`
|
||||||
Txids []string `json:"txids,omitempty"`
|
Txids []string `json:"txids,omitempty"`
|
||||||
Nonce string `json:"nonce,omitempty"`
|
Nonce string `json:"nonce,omitempty"`
|
||||||
UsedTokens int `json:"usedTokens,omitempty"`
|
UsedTokens int `json:"usedTokens,omitempty"`
|
||||||
Tokens []Token `json:"tokens,omitempty"`
|
Tokens []Token `json:"tokens,omitempty"`
|
||||||
Erc20Contract *bchain.Erc20Contract `json:"erc20Contract,omitempty"`
|
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
||||||
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
||||||
// helpers for explorer
|
// helpers for explorer
|
||||||
Filter string `json:"-"`
|
Filter string `json:"-"`
|
||||||
XPubAddresses map[string]struct{} `json:"-"`
|
XPubAddresses map[string]struct{} `json:"-"`
|
||||||
|
|||||||
131
api/worker.go
131
api/worker.go
@ -151,7 +151,10 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
|
|||||||
}
|
}
|
||||||
for a := range addresses {
|
for a := range addresses {
|
||||||
if w.chainType == bchain.ChainEthereumType {
|
if w.chainType == bchain.ChainEthereumType {
|
||||||
// TODO get contract name
|
ci, err := w.db.GetContractInfoForAddress(a)
|
||||||
|
if err == nil && ci != nil && ci.Name != "" {
|
||||||
|
aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
n := w.db.GetAddressAlias(a)
|
n := w.db.GetAddressAlias(a)
|
||||||
if len(n) > 0 {
|
if len(n) > 0 {
|
||||||
@ -535,20 +538,28 @@ func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, add
|
|||||||
glog.Errorf("GetAddrDescFromAddress error %v, contract %v", err, t.Contract)
|
glog.Errorf("GetAddrDescFromAddress error %v, contract %v", err, t.Contract)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
erc20c, err := w.chain.EthereumTypeGetErc20ContractInfo(cd)
|
typeName := bchain.EthereumTokenTypeMap[t.Type]
|
||||||
|
contractInfo, err := w.db.GetContractInfo(cd, typeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("GetErc20ContractInfo error %v, contract %v", err, t.Contract)
|
glog.Errorf("GetContractInfo error %v, contract %v", err, t.Contract)
|
||||||
}
|
}
|
||||||
if erc20c == nil {
|
if contractInfo == nil {
|
||||||
erc20c = &bchain.Erc20Contract{Name: t.Contract}
|
glog.Warningf("Contract %v %v not found in DB", t.Contract, typeName)
|
||||||
|
contractInfo, err = w.chain.GetContractInfo(cd)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("GetContractInfo from chain error %v, contract %v", err, t.Contract)
|
||||||
|
}
|
||||||
|
if contractInfo == nil {
|
||||||
|
contractInfo = &bchain.ContractInfo{Name: t.Contract, Type: bchain.UnknownTokenType}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var value *Amount
|
var value *Amount
|
||||||
var values []TokenTransferValues
|
var values []MultiTokenValue
|
||||||
if t.Type == bchain.ERC1155 {
|
if t.Type == bchain.MultiToken {
|
||||||
values = make([]TokenTransferValues, len(t.IdValues))
|
values = make([]MultiTokenValue, len(t.MultiTokenValues))
|
||||||
for j := range values {
|
for j := range values {
|
||||||
values[j].Id = (*Amount)(&t.IdValues[j].Id)
|
values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id)
|
||||||
values[j].Value = (*Amount)(&t.IdValues[j].Value)
|
values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value = (*Amount)(&t.Value)
|
value = (*Amount)(&t.Value)
|
||||||
@ -556,15 +567,15 @@ func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, add
|
|||||||
aggregateAddress(addresses, t.From)
|
aggregateAddress(addresses, t.From)
|
||||||
aggregateAddress(addresses, t.To)
|
aggregateAddress(addresses, t.To)
|
||||||
tokens[i] = TokenTransfer{
|
tokens[i] = TokenTransfer{
|
||||||
Type: TokenTypeMap[t.Type],
|
Type: typeName,
|
||||||
Token: t.Contract,
|
Token: t.Contract,
|
||||||
From: t.From,
|
From: t.From,
|
||||||
To: t.To,
|
To: t.To,
|
||||||
Value: value,
|
Value: value,
|
||||||
Values: values,
|
MultiTokenValues: values,
|
||||||
Decimals: erc20c.Decimals,
|
Decimals: contractInfo.Decimals,
|
||||||
Name: erc20c.Name,
|
Name: contractInfo.Name,
|
||||||
Symbol: erc20c.Symbol,
|
Symbol: contractInfo.Symbol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tokens
|
return tokens
|
||||||
@ -751,35 +762,41 @@ func computePaging(count, page, itemsOnPage int) (Paging, int, int, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, index int, c *db.AddrContract, details AccountDetails) (*Token, error) {
|
func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, index int, c *db.AddrContract, details AccountDetails) (*Token, error) {
|
||||||
// TODO use db.contracts
|
|
||||||
validContract := true
|
validContract := true
|
||||||
|
typeName := bchain.EthereumTokenTypeMap[c.Type]
|
||||||
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(c.Contract)
|
ci, err := w.db.GetContractInfo(c.Contract, typeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", c.Contract)
|
return nil, errors.Annotatef(err, "GetContractInfo %v", c.Contract)
|
||||||
}
|
}
|
||||||
if ci == nil {
|
if ci == nil {
|
||||||
ci = &bchain.Erc20Contract{}
|
glog.Warningf("Contract %v %v not found in DB", c.Contract, typeName)
|
||||||
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(c.Contract)
|
ci, err = w.chain.GetContractInfo(c.Contract)
|
||||||
if len(addresses) > 0 {
|
if err != nil {
|
||||||
ci.Contract = addresses[0]
|
glog.Errorf("GetContractInfo from chain error %v, contract %v", err, c.Contract)
|
||||||
ci.Name = addresses[0]
|
}
|
||||||
|
if ci == nil {
|
||||||
|
ci = &bchain.ContractInfo{Type: bchain.UnknownTokenType}
|
||||||
|
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(c.Contract)
|
||||||
|
if len(addresses) > 0 {
|
||||||
|
ci.Contract = addresses[0]
|
||||||
|
ci.Name = addresses[0]
|
||||||
|
}
|
||||||
|
validContract = false
|
||||||
}
|
}
|
||||||
validContract = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t := Token{
|
t := Token{
|
||||||
Contract: ci.Contract,
|
Contract: ci.Contract,
|
||||||
Name: ci.Name,
|
Name: ci.Name,
|
||||||
Symbol: ci.Symbol,
|
Symbol: ci.Symbol,
|
||||||
|
Type: typeName,
|
||||||
Transfers: int(c.Txs),
|
Transfers: int(c.Txs),
|
||||||
Decimals: ci.Decimals,
|
Decimals: ci.Decimals,
|
||||||
ContractIndex: strconv.Itoa(index),
|
ContractIndex: strconv.Itoa(index),
|
||||||
}
|
}
|
||||||
// return contract balances/values only at or above AccountDetailsTokenBalances
|
// return contract balances/values only at or above AccountDetailsTokenBalances
|
||||||
if details >= AccountDetailsTokenBalances && validContract {
|
if details >= AccountDetailsTokenBalances && validContract {
|
||||||
if c.Type == bchain.ERC20 {
|
if c.Type == bchain.FungibleToken {
|
||||||
t.Type = ERC20TokenType
|
|
||||||
// get Erc20 Contract Balance from blockchain, balance obtained from adding and subtracting transfers is not correct
|
// get Erc20 Contract Balance from blockchain, balance obtained from adding and subtracting transfers is not correct
|
||||||
b, err := w.chain.EthereumTypeGetErc20ContractBalance(addrDesc, c.Contract)
|
b, err := w.chain.EthereumTypeGetErc20ContractBalance(addrDesc, c.Contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -789,11 +806,6 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
|
|||||||
t.BalanceSat = (*Amount)(b)
|
t.BalanceSat = (*Amount)(b)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if c.Type == bchain.ERC721 {
|
|
||||||
t.Type = ERC771TokenType
|
|
||||||
} else {
|
|
||||||
t.Type = ERC1155TokenType
|
|
||||||
}
|
|
||||||
if len(c.Ids) > 0 {
|
if len(c.Ids) > 0 {
|
||||||
ids := make([]Amount, len(c.Ids))
|
ids := make([]Amount, len(c.Ids))
|
||||||
for j := range ids {
|
for j := range ids {
|
||||||
@ -801,13 +813,13 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
|
|||||||
}
|
}
|
||||||
t.Ids = ids
|
t.Ids = ids
|
||||||
}
|
}
|
||||||
if len(c.IdValues) > 0 {
|
if len(c.MultiTokenValues) > 0 {
|
||||||
idValues := make([]TokenTransferValues, len(c.IdValues))
|
idValues := make([]MultiTokenValue, len(c.MultiTokenValues))
|
||||||
for j := range idValues {
|
for j := range idValues {
|
||||||
idValues[j].Id = (*Amount)(&c.IdValues[j].Id)
|
idValues[j].Id = (*Amount)(&c.MultiTokenValues[j].Id)
|
||||||
idValues[j].Value = (*Amount)(&c.IdValues[j].Value)
|
idValues[j].Value = (*Amount)(&c.MultiTokenValues[j].Value)
|
||||||
}
|
}
|
||||||
t.IdValues = idValues
|
t.MultiTokenValues = idValues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -819,18 +831,25 @@ func (w *Worker) getEthereumContractBalance(addrDesc bchain.AddressDescriptor, i
|
|||||||
func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bchain.AddressDescriptor, details AccountDetails) (*Token, error) {
|
func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bchain.AddressDescriptor, details AccountDetails) (*Token, error) {
|
||||||
var b *big.Int
|
var b *big.Int
|
||||||
validContract := true
|
validContract := true
|
||||||
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(contract)
|
ci, err := w.db.GetContractInfo(contract, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", contract)
|
return nil, errors.Annotatef(err, "GetContractInfo %v", contract)
|
||||||
}
|
}
|
||||||
if ci == nil {
|
if ci == nil {
|
||||||
ci = &bchain.Erc20Contract{}
|
glog.Warningf("Contract %v not found in DB", contract)
|
||||||
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(contract)
|
ci, err = w.chain.GetContractInfo(contract)
|
||||||
if len(addresses) > 0 {
|
if err != nil {
|
||||||
ci.Contract = addresses[0]
|
glog.Errorf("GetContractInfo from chain error %v, contract %v", err, contract)
|
||||||
ci.Name = addresses[0]
|
}
|
||||||
|
if ci == nil {
|
||||||
|
ci = &bchain.ContractInfo{Type: bchain.UnknownTokenType}
|
||||||
|
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(contract)
|
||||||
|
if len(addresses) > 0 {
|
||||||
|
ci.Contract = addresses[0]
|
||||||
|
ci.Name = addresses[0]
|
||||||
|
}
|
||||||
|
validContract = false
|
||||||
}
|
}
|
||||||
validContract = false
|
|
||||||
}
|
}
|
||||||
// do not read contract balances etc in case of Basic option
|
// do not read contract balances etc in case of Basic option
|
||||||
if details >= AccountDetailsTokenBalances && validContract {
|
if details >= AccountDetailsTokenBalances && validContract {
|
||||||
@ -843,7 +862,7 @@ func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bch
|
|||||||
b = nil
|
b = nil
|
||||||
}
|
}
|
||||||
return &Token{
|
return &Token{
|
||||||
Type: ERC20TokenType,
|
Type: ci.Type,
|
||||||
BalanceSat: (*Amount)(b),
|
BalanceSat: (*Amount)(b),
|
||||||
Contract: ci.Contract,
|
Contract: ci.Contract,
|
||||||
Name: ci.Name,
|
Name: ci.Name,
|
||||||
@ -854,11 +873,11 @@ func (w *Worker) getEthereumContractBalanceFromBlockchain(addrDesc, contract bch
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.Erc20Contract, uint64, int, int, int, error) {
|
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.ContractInfo, uint64, int, int, int, error) {
|
||||||
var (
|
var (
|
||||||
ba *db.AddrBalance
|
ba *db.AddrBalance
|
||||||
tokens []Token
|
tokens []Token
|
||||||
ci *bchain.Erc20Contract
|
ci *bchain.ContractInfo
|
||||||
n uint64
|
n uint64
|
||||||
nonContractTxs int
|
nonContractTxs int
|
||||||
internalTxs int
|
internalTxs int
|
||||||
@ -912,7 +931,7 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
|||||||
}
|
}
|
||||||
tokens = tokens[:j]
|
tokens = tokens[:j]
|
||||||
}
|
}
|
||||||
ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
|
ci, err = w.db.GetContractInfo(addrDesc, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, 0, 0, 0, err
|
return nil, nil, nil, 0, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
@ -1043,7 +1062,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
var (
|
var (
|
||||||
ba *db.AddrBalance
|
ba *db.AddrBalance
|
||||||
tokens []Token
|
tokens []Token
|
||||||
erc20c *bchain.Erc20Contract
|
contractInfo *bchain.ContractInfo
|
||||||
txm []string
|
txm []string
|
||||||
txs []*Tx
|
txs []*Tx
|
||||||
txids []string
|
txids []string
|
||||||
@ -1062,7 +1081,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
}
|
}
|
||||||
if w.chainType == bchain.ChainEthereumType {
|
if w.chainType == bchain.ChainEthereumType {
|
||||||
var n uint64
|
var n uint64
|
||||||
ba, tokens, erc20c, n, nonTokenTxs, internalTxs, totalResults, err = w.getEthereumTypeAddressBalances(addrDesc, option, filter)
|
ba, tokens, contractInfo, n, nonTokenTxs, internalTxs, totalResults, err = w.getEthereumTypeAddressBalances(addrDesc, option, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1173,7 +1192,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
Transactions: txs,
|
Transactions: txs,
|
||||||
Txids: txids,
|
Txids: txids,
|
||||||
Tokens: tokens,
|
Tokens: tokens,
|
||||||
Erc20Contract: erc20c,
|
ContractInfo: contractInfo,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
AddressAliases: w.getAddressAliases(addresses),
|
AddressAliases: w.getAddressAliases(addresses),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,7 +266,7 @@ func (w *Worker) tokenFromXpubAddress(data *xpubData, ad *xpubAddress, changeInd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Token{
|
return Token{
|
||||||
Type: XPUBAddressTokenType,
|
Type: bchain.XPUBAddressTokenType,
|
||||||
Name: address,
|
Name: address,
|
||||||
Decimals: w.chainParser.AmountDecimals(),
|
Decimals: w.chainParser.AmountDecimals(),
|
||||||
BalanceSat: (*Amount)(balance),
|
BalanceSat: (*Amount)(balance),
|
||||||
|
|||||||
@ -54,8 +54,8 @@ func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint
|
|||||||
return 0, errors.New("Not supported")
|
return 0, errors.New("Not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetErc20ContractInfo is not supported
|
// GetContractInfo is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetErc20ContractInfo(contractDesc AddressDescriptor) (*Erc20Contract, error) {
|
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("Not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -321,13 +321,13 @@ func (c *blockChainWithMetrics) EthereumTypeEstimateGas(params map[string]interf
|
|||||||
return c.b.EthereumTypeEstimateGas(params)
|
return c.b.EthereumTypeEstimateGas(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (v *bchain.Erc20Contract, err error) {
|
func (c *blockChainWithMetrics) GetContractInfo(contractDesc bchain.AddressDescriptor) (v *bchain.ContractInfo, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetContractInfo", s, err) }(time.Now())
|
||||||
return c.b.EthereumTypeGetErc20ContractInfo(contractDesc)
|
return c.b.GetContractInfo(contractDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (v *big.Int, err error) {
|
func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (v *big.Int, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractInfo", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractBalance", s, err) }(time.Now())
|
||||||
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
)
|
)
|
||||||
@ -28,9 +26,6 @@ const contractSymbolSignature = "0x95d89b41"
|
|||||||
const contractDecimalsSignature = "0x313ce567"
|
const contractDecimalsSignature = "0x313ce567"
|
||||||
const contractBalanceOf = "0x70a08231"
|
const contractBalanceOf = "0x70a08231"
|
||||||
|
|
||||||
var cachedContracts = make(map[string]*bchain.Erc20Contract)
|
|
||||||
var cachedContractsMux sync.Mutex
|
|
||||||
|
|
||||||
func addressFromPaddedHex(s string) (string, error) {
|
func addressFromPaddedHex(s string) (string, error) {
|
||||||
var t big.Int
|
var t big.Int
|
||||||
var ok bool
|
var ok bool
|
||||||
@ -48,16 +43,16 @@ func addressFromPaddedHex(s string) (string, error) {
|
|||||||
|
|
||||||
func processTransferEvent(l *bchain.RpcLog) (*bchain.TokenTransfer, error) {
|
func processTransferEvent(l *bchain.RpcLog) (*bchain.TokenTransfer, error) {
|
||||||
tl := len(l.Topics)
|
tl := len(l.Topics)
|
||||||
var ttt bchain.TokenTransferType
|
var ttt bchain.TokenType
|
||||||
var value big.Int
|
var value big.Int
|
||||||
if tl == 3 {
|
if tl == 3 {
|
||||||
ttt = bchain.ERC20
|
ttt = bchain.FungibleToken
|
||||||
_, ok := value.SetString(l.Data, 0)
|
_, ok := value.SetString(l.Data, 0)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("ERC20 log Data is not a number")
|
return nil, errors.New("ERC20 log Data is not a number")
|
||||||
}
|
}
|
||||||
} else if tl == 4 {
|
} else if tl == 4 {
|
||||||
ttt = bchain.ERC721
|
ttt = bchain.NonFungibleToken
|
||||||
_, ok := value.SetString(l.Topics[3], 0)
|
_, ok := value.SetString(l.Topics[3], 0)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("ERC721 log Topics[3] is not a number")
|
return nil, errors.New("ERC721 log Topics[3] is not a number")
|
||||||
@ -105,11 +100,11 @@ func processERC1155TransferSingleEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
|
|||||||
return nil, errors.New("ERC1155 log Data value is not a number")
|
return nil, errors.New("ERC1155 log Data value is not a number")
|
||||||
}
|
}
|
||||||
return &bchain.TokenTransfer{
|
return &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: EIP55AddressFromAddress(l.Address),
|
Contract: EIP55AddressFromAddress(l.Address),
|
||||||
From: EIP55AddressFromAddress(from),
|
From: EIP55AddressFromAddress(from),
|
||||||
To: EIP55AddressFromAddress(to),
|
To: EIP55AddressFromAddress(to),
|
||||||
IdValues: []bchain.TokenTransferIdValue{{Id: id, Value: value}},
|
MultiTokenValues: []bchain.MultiTokenValue{{Id: id, Value: value}},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +145,7 @@ func processERC1155TransferBatchEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
|
|||||||
if countIds != countValues {
|
if countIds != countValues {
|
||||||
return nil, errors.New("ERC1155 TransferBatch, count values and ids does not match")
|
return nil, errors.New("ERC1155 TransferBatch, count values and ids does not match")
|
||||||
}
|
}
|
||||||
idValues := make([]bchain.TokenTransferIdValue, countValues)
|
idValues := make([]bchain.MultiTokenValue, countValues)
|
||||||
for i := 0; i < countValues; i++ {
|
for i := 0; i < countValues; i++ {
|
||||||
var id, value big.Int
|
var id, value big.Int
|
||||||
o := offsetIds + 64 + 64*i
|
o := offsetIds + 64 + 64*i
|
||||||
@ -163,14 +158,14 @@ func processERC1155TransferBatchEvent(l *bchain.RpcLog) (*bchain.TokenTransfer,
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("ERC1155 log Data value is not a number")
|
return nil, errors.New("ERC1155 log Data value is not a number")
|
||||||
}
|
}
|
||||||
idValues[i] = bchain.TokenTransferIdValue{Id: id, Value: value}
|
idValues[i] = bchain.MultiTokenValue{Id: id, Value: value}
|
||||||
}
|
}
|
||||||
return &bchain.TokenTransfer{
|
return &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: EIP55AddressFromAddress(l.Address),
|
Contract: EIP55AddressFromAddress(l.Address),
|
||||||
From: EIP55AddressFromAddress(from),
|
From: EIP55AddressFromAddress(from),
|
||||||
To: EIP55AddressFromAddress(to),
|
To: EIP55AddressFromAddress(to),
|
||||||
IdValues: idValues,
|
MultiTokenValues: idValues,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
func contractGetTransfersFromLog(logs []*bchain.RpcLog) (bchain.TokenTransfers, error) {
|
func contractGetTransfersFromLog(logs []*bchain.RpcLog) (bchain.TokenTransfers, error) {
|
||||||
@ -214,7 +209,7 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
|
|||||||
return nil, errors.New("Data is not a number")
|
return nil, errors.New("Data is not a number")
|
||||||
}
|
}
|
||||||
r = append(r, &bchain.TokenTransfer{
|
r = append(r, &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: EIP55AddressFromAddress(tx.To),
|
Contract: EIP55AddressFromAddress(tx.To),
|
||||||
From: EIP55AddressFromAddress(tx.From),
|
From: EIP55AddressFromAddress(tx.From),
|
||||||
To: EIP55AddressFromAddress(to),
|
To: EIP55AddressFromAddress(to),
|
||||||
@ -238,7 +233,7 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
|
|||||||
return nil, errors.New("Data is not a number")
|
return nil, errors.New("Data is not a number")
|
||||||
}
|
}
|
||||||
r = append(r, &bchain.TokenTransfer{
|
r = append(r, &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: EIP55AddressFromAddress(tx.To),
|
Contract: EIP55AddressFromAddress(tx.To),
|
||||||
From: EIP55AddressFromAddress(from),
|
From: EIP55AddressFromAddress(from),
|
||||||
To: EIP55AddressFromAddress(to),
|
To: EIP55AddressFromAddress(to),
|
||||||
@ -262,56 +257,52 @@ func (b *EthereumRPC) ethCall(data, to string) (string, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetErc20ContractInfo returns information about ERC20 contract
|
func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
|
||||||
func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) {
|
var contract bchain.ContractInfo
|
||||||
cds := string(contractDesc)
|
data, err := b.ethCall(contractNameSignature, address)
|
||||||
cachedContractsMux.Lock()
|
if err != nil {
|
||||||
contract, found := cachedContracts[cds]
|
// ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
|
||||||
cachedContractsMux.Unlock()
|
// and returning error "execution reverted" for some non contract addresses
|
||||||
if !found {
|
// https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672
|
||||||
address := EIP55Address(contractDesc)
|
// glog.Warning(errors.Annotatef(err, "Contract NameSignature %v", address))
|
||||||
data, err := b.ethCall(contractNameSignature, address)
|
return nil, nil
|
||||||
if err != nil {
|
// return nil, errors.Annotatef(err, "erc20NameSignature %v", address)
|
||||||
// ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
|
|
||||||
// and returning error "execution reverted" for some non contract addresses
|
|
||||||
// https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672
|
|
||||||
glog.Warning(errors.Annotatef(err, "erc20NameSignature %v", address))
|
|
||||||
return nil, nil
|
|
||||||
// return nil, errors.Annotatef(err, "erc20NameSignature %v", address)
|
|
||||||
}
|
|
||||||
name := parseSimpleStringProperty(data)
|
|
||||||
if name != "" {
|
|
||||||
data, err = b.ethCall(contractSymbolSignature, address)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warning(errors.Annotatef(err, "erc20SymbolSignature %v", address))
|
|
||||||
return nil, nil
|
|
||||||
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
|
||||||
}
|
|
||||||
symbol := parseSimpleStringProperty(data)
|
|
||||||
data, err = b.ethCall(contractDecimalsSignature, address)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warning(errors.Annotatef(err, "erc20DecimalsSignature %v", address))
|
|
||||||
// return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
|
||||||
}
|
|
||||||
contract = &bchain.Erc20Contract{
|
|
||||||
Contract: address,
|
|
||||||
Name: name,
|
|
||||||
Symbol: symbol,
|
|
||||||
}
|
|
||||||
d := parseSimpleNumericProperty(data)
|
|
||||||
if d != nil {
|
|
||||||
contract.Decimals = int(uint8(d.Uint64()))
|
|
||||||
} else {
|
|
||||||
contract.Decimals = EtherAmountDecimalPoint
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contract = nil
|
|
||||||
}
|
|
||||||
cachedContractsMux.Lock()
|
|
||||||
cachedContracts[cds] = contract
|
|
||||||
cachedContractsMux.Unlock()
|
|
||||||
}
|
}
|
||||||
return contract, nil
|
name := parseSimpleStringProperty(data)
|
||||||
|
if name != "" {
|
||||||
|
data, err = b.ethCall(contractSymbolSignature, address)
|
||||||
|
if err != nil {
|
||||||
|
// glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
|
||||||
|
return nil, nil
|
||||||
|
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
||||||
|
}
|
||||||
|
symbol := parseSimpleStringProperty(data)
|
||||||
|
data, _ = b.ethCall(contractDecimalsSignature, address)
|
||||||
|
// if err != nil {
|
||||||
|
// glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
|
||||||
|
// // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
||||||
|
// }
|
||||||
|
contract = bchain.ContractInfo{
|
||||||
|
Contract: address,
|
||||||
|
Name: name,
|
||||||
|
Symbol: symbol,
|
||||||
|
}
|
||||||
|
d := parseSimpleNumericProperty(data)
|
||||||
|
if d != nil {
|
||||||
|
contract.Decimals = int(uint8(d.Uint64()))
|
||||||
|
} else {
|
||||||
|
contract.Decimals = EtherAmountDecimalPoint
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &contract, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContractInfo returns information about a contract
|
||||||
|
func (b *EthereumRPC) GetContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.ContractInfo, error) {
|
||||||
|
address := EIP55Address(contractDesc)
|
||||||
|
return b.fetchContractInfo(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
||||||
|
|||||||
@ -133,7 +133,7 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: bchain.TokenTransfers{
|
want: bchain.TokenTransfers{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: "0x5689b918D34C038901870105A6C7fc24744D31eB",
|
Contract: "0x5689b918D34C038901870105A6C7fc24744D31eB",
|
||||||
From: "0x0a206d4d5ff79cb5069def7fe3598421cff09391",
|
From: "0x0a206d4d5ff79cb5069def7fe3598421cff09391",
|
||||||
To: "0x6a016d7eec560549ffa0fbdb7f15c2b27302087f",
|
To: "0x6a016d7eec560549ffa0fbdb7f15c2b27302087f",
|
||||||
@ -171,11 +171,11 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: bchain.TokenTransfers{
|
want: bchain.TokenTransfers{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
|
Contract: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
|
||||||
From: "0xa3950b823cb063dd9afc0d27f35008b805b3ed53",
|
From: "0xa3950b823cb063dd9afc0d27f35008b805b3ed53",
|
||||||
To: "0x4392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
|
To: "0x4392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
|
||||||
IdValues: []bchain.TokenTransferIdValue{{Id: *big.NewInt(150), Value: *big.NewInt(0x11)}},
|
MultiTokenValues: []bchain.MultiTokenValue{{Id: *big.NewInt(150), Value: *big.NewInt(0x11)}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -195,11 +195,11 @@ func Test_contractGetTransfersFromLog(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: bchain.TokenTransfers{
|
want: bchain.TokenTransfers{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: "0x6c42c26a081c2f509f8bb68fb7ac3062311ccfb7",
|
Contract: "0x6c42c26a081c2f509f8bb68fb7ac3062311ccfb7",
|
||||||
From: "0x0000000000000000000000000000000000000000",
|
From: "0x0000000000000000000000000000000000000000",
|
||||||
To: "0x5dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
|
To: "0x5dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{Id: *big.NewInt(1776), Value: *big.NewInt(1)},
|
{Id: *big.NewInt(1776), Value: *big.NewInt(1)},
|
||||||
{Id: *big.NewInt(1898), Value: *big.NewInt(10)},
|
{Id: *big.NewInt(1898), Value: *big.NewInt(10)},
|
||||||
},
|
},
|
||||||
@ -247,7 +247,7 @@ func Test_contractGetTransfersFromTx(t *testing.T) {
|
|||||||
args: (b1.Txs[1].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
args: (b1.Txs[1].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
||||||
want: bchain.TokenTransfers{
|
want: bchain.TokenTransfers{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
|
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
|
||||||
From: "0x20cd153de35d469ba46127a0c8f18626b59a256a",
|
From: "0x20cd153de35d469ba46127a0c8f18626b59a256a",
|
||||||
To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
|
To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
|
||||||
@ -260,7 +260,7 @@ func Test_contractGetTransfersFromTx(t *testing.T) {
|
|||||||
args: (b2.Txs[2].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
args: (b2.Txs[2].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
||||||
want: bchain.TokenTransfers{
|
want: bchain.TokenTransfers{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: "0xcda9fc258358ecaa88845f19af595e908bb7efe9",
|
Contract: "0xcda9fc258358ecaa88845f19af595e908bb7efe9",
|
||||||
From: "0x837e3f699d85a4b0b99894567e9233dfb1dcb081",
|
From: "0x837e3f699d85a4b0b99894567e9233dfb1dcb081",
|
||||||
To: "0x7b62eb7fe80350dc7ec945c0b73242cb9877fb1b",
|
To: "0x7b62eb7fe80350dc7ec945c0b73242cb9877fb1b",
|
||||||
|
|||||||
@ -39,8 +39,8 @@ func parseSimpleStringProperty(data string) string {
|
|||||||
if len(data) > 128 {
|
if len(data) > 128 {
|
||||||
n := parseSimpleNumericProperty(data[64:128])
|
n := parseSimpleNumericProperty(data[64:128])
|
||||||
if n != nil {
|
if n != nil {
|
||||||
l := n.Uint64()
|
l := n.Int64()
|
||||||
if l > 0 && 2*int(l) <= len(data)-128 {
|
if l > 0 && int(l) <= ((len(data)-128)>>1) {
|
||||||
b, err := hex.DecodeString(data[128 : 128+2*l])
|
b, err := hex.DecodeString(data[128 : 128+2*l])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return string(b)
|
return string(b)
|
||||||
|
|||||||
@ -45,6 +45,11 @@ func Test_parseSimpleStringProperty(t *testing.T) {
|
|||||||
args: "0x2234880850896048596206002535425366538144616734015984380565810000",
|
args: "0x2234880850896048596206002535425366538144616734015984380565810000",
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "garbage",
|
||||||
|
args: "6080604052600436106100225760003560e01c80630cbcae701461003957610031565b366100315761002f610077565b005b61002f610077565b34801561004557600080fd5b5061004e61014e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000061011c565b60043560601b60601c6bca11c0de15dead10cced00006000195460a01c036100e9577f696d706c6f63000000000000000000000000000000000000000000000000000060005260206000fd5b8060001955005b60405136810160405236600082376000803683600019545af43d6000833e80610117573d82fd5b503d81f35b80330361014357602436036101435763ca11c0de60003560e01c036101435761014361009d565b61014b6100f0565b50565b600073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff541660005260206000f3fea2646970667358221220f27ad3f3b75609baa5d26d65ec1001c4a59f38e89088d6b47517c1cd1faf22ab64736f6c634300080d0033",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
@ -537,23 +537,37 @@ type rpcTraceResult struct {
|
|||||||
Result rpcCallTrace `json:"result"`
|
Result rpcCallTrace `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData) {
|
func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo {
|
||||||
|
ci, err := b.fetchContractInfo(contract)
|
||||||
|
if ci == nil || err != nil {
|
||||||
|
ci = &bchain.ContractInfo{
|
||||||
|
Contract: contract,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ci.Type = bchain.UnknownTokenType
|
||||||
|
ci.CreatedInBlock = height
|
||||||
|
return ci
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo {
|
||||||
value, err := hexutil.DecodeBig(call.Value)
|
value, err := hexutil.DecodeBig(call.Value)
|
||||||
if call.Type == "CREATE" {
|
if call.Type == "CREATE" {
|
||||||
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
||||||
Type: bchain.CREATE,
|
Type: bchain.CREATE,
|
||||||
Value: *value,
|
Value: *value,
|
||||||
From: call.From,
|
From: call.From,
|
||||||
To: call.To,
|
To: call.To, // new contract address
|
||||||
})
|
})
|
||||||
|
contracts = append(contracts, *b.getCreationContractInfo(call.To, blockHeight))
|
||||||
|
|
||||||
} else if call.Type == "SELFDESTRUCT" {
|
} else if call.Type == "SELFDESTRUCT" {
|
||||||
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
||||||
Type: bchain.SELFDESTRUCT,
|
Type: bchain.SELFDESTRUCT,
|
||||||
Value: *value,
|
Value: *value,
|
||||||
From: call.From,
|
From: call.From, // destroyed contract address
|
||||||
To: call.To,
|
To: call.To,
|
||||||
})
|
})
|
||||||
|
contracts = append(contracts, bchain.ContractInfo{Contract: call.From, DestructedInBlock: blockHeight})
|
||||||
} else if err == nil && (value.BitLen() > 0 || b.ChainConfig.ProcessZeroInternalTransactions) {
|
} else if err == nil && (value.BitLen() > 0 || b.ChainConfig.ProcessZeroInternalTransactions) {
|
||||||
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
||||||
Value: *value,
|
Value: *value,
|
||||||
@ -565,13 +579,15 @@ func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInt
|
|||||||
d.Error = call.Error
|
d.Error = call.Error
|
||||||
}
|
}
|
||||||
for i := range call.Calls {
|
for i := range call.Calls {
|
||||||
b.processCallTrace(&call.Calls[i], d)
|
contracts = b.processCallTrace(&call.Calls[i], d, contracts, blockHeight)
|
||||||
}
|
}
|
||||||
|
return contracts
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, error) {
|
func (b *EthereumRPC) getInternalDataForBlock(blockHash string, blockHeight uint32, transactions []bchain.RpcTransaction) ([]bchain.EthereumInternalData, []bchain.ContractInfo, error) {
|
||||||
data := make([]bchain.EthereumInternalData, len(transactions))
|
data := make([]bchain.EthereumInternalData, len(transactions))
|
||||||
|
contracts := make([]bchain.ContractInfo, 0)
|
||||||
if ProcessInternalTransactions {
|
if ProcessInternalTransactions {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -579,11 +595,11 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
|
|||||||
err := b.rpc.CallContext(ctx, &trace, "debug_traceBlockByHash", blockHash, map[string]interface{}{"tracer": "callTracer"})
|
err := b.rpc.CallContext(ctx, &trace, "debug_traceBlockByHash", blockHash, map[string]interface{}{"tracer": "callTracer"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("debug_traceBlockByHash block ", blockHash, ", error ", err)
|
glog.Error("debug_traceBlockByHash block ", blockHash, ", error ", err)
|
||||||
return data, err
|
return data, contracts, err
|
||||||
}
|
}
|
||||||
if len(trace) != len(data) {
|
if len(trace) != len(data) {
|
||||||
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: trace length does not match block length ", len(trace), "!=", len(data))
|
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: trace length does not match block length ", len(trace), "!=", len(data))
|
||||||
return data, err
|
return data, contracts, err
|
||||||
}
|
}
|
||||||
for i, result := range trace {
|
for i, result := range trace {
|
||||||
r := &result.Result
|
r := &result.Result
|
||||||
@ -591,11 +607,12 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
|
|||||||
if r.Type == "CREATE" {
|
if r.Type == "CREATE" {
|
||||||
d.Type = bchain.CREATE
|
d.Type = bchain.CREATE
|
||||||
d.Contract = r.To
|
d.Contract = r.To
|
||||||
|
contracts = append(contracts, *b.getCreationContractInfo(d.Contract, blockHeight))
|
||||||
} else if r.Type == "SELFDESTRUCT" {
|
} else if r.Type == "SELFDESTRUCT" {
|
||||||
d.Type = bchain.SELFDESTRUCT
|
d.Type = bchain.SELFDESTRUCT
|
||||||
}
|
}
|
||||||
for j := range r.Calls {
|
for j := range r.Calls {
|
||||||
b.processCallTrace(&r.Calls[j], d)
|
contracts = b.processCallTrace(&r.Calls[j], d, contracts, blockHeight)
|
||||||
}
|
}
|
||||||
if r.Error != "" {
|
if r.Error != "" {
|
||||||
baseError := PackInternalTransactionError(r.Error)
|
baseError := PackInternalTransactionError(r.Error)
|
||||||
@ -620,7 +637,7 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, contracts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock returns block with given hash or height, hash has precedence if both passed
|
// GetBlock returns block with given hash or height, hash has precedence if both passed
|
||||||
@ -642,15 +659,16 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
|
|||||||
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
|
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
|
||||||
}
|
}
|
||||||
// get block events
|
// get block events
|
||||||
|
// TODO - could be possibly done in parallel to getInternalDataForBlock
|
||||||
logs, ens, err := b.processEventsForBlock(head.Number)
|
logs, ens, err := b.processEventsForBlock(head.Number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// error fetching internal data does not stop the block processing
|
// error fetching internal data does not stop the block processing
|
||||||
var blockSpecificData *bchain.EthereumBlockSpecificData
|
var blockSpecificData *bchain.EthereumBlockSpecificData
|
||||||
internalData, err := b.getInternalDataForBlock(head.Hash, body.Transactions)
|
internalData, contracts, err := b.getInternalDataForBlock(head.Hash, bbh.Height, body.Transactions)
|
||||||
// pass internalData error and ENS records in blockSpecificData to be stored
|
// pass internalData error and ENS records in blockSpecificData to be stored
|
||||||
if err != nil || len(ens) > 0 {
|
if err != nil || len(ens) > 0 || len(contracts) > 0 {
|
||||||
blockSpecificData = &bchain.EthereumBlockSpecificData{}
|
blockSpecificData = &bchain.EthereumBlockSpecificData{}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockSpecificData.InternalDataError = err.Error()
|
blockSpecificData.InternalDataError = err.Error()
|
||||||
@ -658,7 +676,11 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
|
|||||||
}
|
}
|
||||||
if len(ens) > 0 {
|
if len(ens) > 0 {
|
||||||
blockSpecificData.AddressAliasRecords = ens
|
blockSpecificData.AddressAliasRecords = ens
|
||||||
glog.Info("ENS", ens)
|
// glog.Info("ENS", ens)
|
||||||
|
}
|
||||||
|
if len(contracts) > 0 {
|
||||||
|
blockSpecificData.Contracts = contracts
|
||||||
|
// glog.Info("Contracts", contracts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,6 +113,27 @@ type MempoolTx struct {
|
|||||||
CoinSpecificData interface{} `json:"-"`
|
CoinSpecificData interface{} `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TokenType - type of token
|
||||||
|
type TokenType int
|
||||||
|
|
||||||
|
// TokenType enumeration
|
||||||
|
const (
|
||||||
|
FungibleToken = TokenType(iota) // ERC20
|
||||||
|
NonFungibleToken // ERC721
|
||||||
|
MultiToken // ERC1155
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenTypeName specifies type of token
|
||||||
|
type TokenTypeName string
|
||||||
|
|
||||||
|
// Token types
|
||||||
|
const (
|
||||||
|
UnknownTokenType TokenTypeName = ""
|
||||||
|
|
||||||
|
// XPUBAddressTokenType is address derived from xpub
|
||||||
|
XPUBAddressTokenType TokenTypeName = "XPUBAddress"
|
||||||
|
)
|
||||||
|
|
||||||
// TokenTransfers is array of TokenTransfer
|
// TokenTransfers is array of TokenTransfer
|
||||||
type TokenTransfers []*TokenTransfer
|
type TokenTransfers []*TokenTransfer
|
||||||
|
|
||||||
@ -286,13 +307,13 @@ type BlockChain interface {
|
|||||||
EstimateFee(blocks int) (big.Int, error)
|
EstimateFee(blocks int) (big.Int, error)
|
||||||
SendRawTransaction(tx string) (string, error)
|
SendRawTransaction(tx string) (string, error)
|
||||||
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
||||||
|
GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error)
|
||||||
// parser
|
// parser
|
||||||
GetChainParser() BlockChainParser
|
GetChainParser() BlockChainParser
|
||||||
// EthereumType specific
|
// EthereumType specific
|
||||||
EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error)
|
EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error)
|
||||||
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
||||||
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
||||||
EthereumTypeGetErc20ContractInfo(contractDesc AddressDescriptor) (*Erc20Contract, error)
|
|
||||||
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,16 +47,6 @@ const (
|
|||||||
SELFDESTRUCT
|
SELFDESTRUCT
|
||||||
)
|
)
|
||||||
|
|
||||||
// TokenTransferType - type of token transfer
|
|
||||||
type TokenTransferType int
|
|
||||||
|
|
||||||
// TokenTransferType enumeration
|
|
||||||
const (
|
|
||||||
ERC20 = TokenTransferType(iota)
|
|
||||||
ERC721
|
|
||||||
ERC1155
|
|
||||||
)
|
|
||||||
|
|
||||||
// EthereumInternalTransaction contains internal transfers
|
// EthereumInternalTransaction contains internal transfers
|
||||||
type EthereumInternalData struct {
|
type EthereumInternalData struct {
|
||||||
Type EthereumInternalTransactionType `json:"type"`
|
Type EthereumInternalTransactionType `json:"type"`
|
||||||
@ -65,27 +55,41 @@ type EthereumInternalData struct {
|
|||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erc20Contract contains info about ERC20 contract
|
// ContractInfo contains info about ERC20 contract
|
||||||
type Erc20Contract struct {
|
type ContractInfo struct {
|
||||||
Contract string `json:"contract"`
|
Type TokenTypeName `json:"type"`
|
||||||
Name string `json:"name"`
|
Contract string `json:"contract"`
|
||||||
Symbol string `json:"symbol"`
|
Name string `json:"name"`
|
||||||
Decimals int `json:"decimals"`
|
Symbol string `json:"symbol"`
|
||||||
|
Decimals int `json:"decimals"`
|
||||||
|
CreatedInBlock uint32 `json:"createdInBlock,omitempty"`
|
||||||
|
DestructedInBlock uint32 `json:"destructedInBlock,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenTransferIdValue struct {
|
// Ethereum token type names
|
||||||
|
const (
|
||||||
|
ERC20TokenType TokenTypeName = "ERC20"
|
||||||
|
ERC771TokenType TokenTypeName = "ERC721"
|
||||||
|
ERC1155TokenType TokenTypeName = "ERC1155"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EthereumTokenTypeMap maps bchain.TokenType to TokenTypeName
|
||||||
|
// the map must match all bchain.TokenType to avoid index out of range panic
|
||||||
|
var EthereumTokenTypeMap []TokenTypeName = []TokenTypeName{ERC20TokenType, ERC771TokenType, ERC1155TokenType}
|
||||||
|
|
||||||
|
type MultiTokenValue struct {
|
||||||
Id big.Int
|
Id big.Int
|
||||||
Value big.Int
|
Value big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenTransfer contains a single ERC20/ERC721/ERC1155 token transfer
|
// TokenTransfer contains a single token transfer
|
||||||
type TokenTransfer struct {
|
type TokenTransfer struct {
|
||||||
Type TokenTransferType
|
Type TokenType
|
||||||
Contract string
|
Contract string
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
Value big.Int
|
Value big.Int
|
||||||
IdValues []TokenTransferIdValue
|
MultiTokenValues []MultiTokenValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// RpcTransaction is returned by eth_getTransactionByHash
|
// RpcTransaction is returned by eth_getTransactionByHash
|
||||||
@ -138,4 +142,5 @@ type AddressAliasRecord struct {
|
|||||||
type EthereumBlockSpecificData struct {
|
type EthereumBlockSpecificData struct {
|
||||||
InternalDataError string
|
InternalDataError string
|
||||||
AddressAliasRecords []AddressAliasRecord
|
AddressAliasRecords []AddressAliasRecord
|
||||||
|
Contracts []ContractInfo
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
vlq "github.com/bsm/go-vlq"
|
||||||
"github.com/flier/gorocksdb"
|
"github.com/flier/gorocksdb"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
@ -18,12 +19,12 @@ const ContractIndexOffset = 2
|
|||||||
|
|
||||||
// AddrContract is Contract address with number of transactions done by given address
|
// AddrContract is Contract address with number of transactions done by given address
|
||||||
type AddrContract struct {
|
type AddrContract struct {
|
||||||
Type bchain.TokenTransferType
|
Type bchain.TokenType
|
||||||
Contract bchain.AddressDescriptor
|
Contract bchain.AddressDescriptor
|
||||||
Txs uint
|
Txs uint
|
||||||
Value big.Int // single value of ERC20
|
Value big.Int // single value of ERC20
|
||||||
Ids []big.Int // multiple ERC721 tokens
|
Ids []big.Int // multiple ERC721 tokens
|
||||||
IdValues []bchain.TokenTransferIdValue // multiple ERC1155 tokens
|
MultiTokenValues []bchain.MultiTokenValue // multiple ERC1155 tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddrContracts contains number of transactions and contracts for an address
|
// AddrContracts contains number of transactions and contracts for an address
|
||||||
@ -48,10 +49,10 @@ func packAddrContracts(acs *AddrContracts) []byte {
|
|||||||
buf = append(buf, ac.Contract...)
|
buf = append(buf, ac.Contract...)
|
||||||
l = packVaruint(uint(ac.Type)+ac.Txs<<2, varBuf)
|
l = packVaruint(uint(ac.Type)+ac.Txs<<2, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
if ac.Type == bchain.ERC20 {
|
if ac.Type == bchain.FungibleToken {
|
||||||
l = packBigint(&ac.Value, varBuf)
|
l = packBigint(&ac.Value, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
} else if ac.Type == bchain.ERC721 {
|
} else if ac.Type == bchain.NonFungibleToken {
|
||||||
l = packVaruint(uint(len(ac.Ids)), varBuf)
|
l = packVaruint(uint(len(ac.Ids)), varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
for i := range ac.Ids {
|
for i := range ac.Ids {
|
||||||
@ -59,12 +60,12 @@ func packAddrContracts(acs *AddrContracts) []byte {
|
|||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
}
|
}
|
||||||
} else { // bchain.ERC1155
|
} else { // bchain.ERC1155
|
||||||
l = packVaruint(uint(len(ac.IdValues)), varBuf)
|
l = packVaruint(uint(len(ac.MultiTokenValues)), varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
for i := range ac.IdValues {
|
for i := range ac.MultiTokenValues {
|
||||||
l = packBigint(&ac.IdValues[i].Id, varBuf)
|
l = packBigint(&ac.MultiTokenValues[i].Id, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
l = packBigint(&ac.IdValues[i].Value, varBuf)
|
l = packBigint(&ac.MultiTokenValues[i].Value, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,21 +88,21 @@ func unpackAddrContracts(buf []byte, addrDesc bchain.AddressDescriptor) (*AddrCo
|
|||||||
contract := append(bchain.AddressDescriptor(nil), buf[:eth.EthereumTypeAddressDescriptorLen]...)
|
contract := append(bchain.AddressDescriptor(nil), buf[:eth.EthereumTypeAddressDescriptorLen]...)
|
||||||
txs, l := unpackVaruint(buf[eth.EthereumTypeAddressDescriptorLen:])
|
txs, l := unpackVaruint(buf[eth.EthereumTypeAddressDescriptorLen:])
|
||||||
buf = buf[eth.EthereumTypeAddressDescriptorLen+l:]
|
buf = buf[eth.EthereumTypeAddressDescriptorLen+l:]
|
||||||
ttt := bchain.TokenTransferType(txs & 3)
|
ttt := bchain.TokenType(txs & 3)
|
||||||
txs >>= 2
|
txs >>= 2
|
||||||
ac := AddrContract{
|
ac := AddrContract{
|
||||||
Type: ttt,
|
Type: ttt,
|
||||||
Contract: contract,
|
Contract: contract,
|
||||||
Txs: txs,
|
Txs: txs,
|
||||||
}
|
}
|
||||||
if ttt == bchain.ERC20 {
|
if ttt == bchain.FungibleToken {
|
||||||
b, ll := unpackBigint(buf)
|
b, ll := unpackBigint(buf)
|
||||||
buf = buf[ll:]
|
buf = buf[ll:]
|
||||||
ac.Value = b
|
ac.Value = b
|
||||||
} else {
|
} else {
|
||||||
len, ll := unpackVaruint(buf)
|
len, ll := unpackVaruint(buf)
|
||||||
buf = buf[ll:]
|
buf = buf[ll:]
|
||||||
if ttt == bchain.ERC721 {
|
if ttt == bchain.NonFungibleToken {
|
||||||
ac.Ids = make([]big.Int, len)
|
ac.Ids = make([]big.Int, len)
|
||||||
for i := uint(0); i < len; i++ {
|
for i := uint(0); i < len; i++ {
|
||||||
b, ll := unpackBigint(buf)
|
b, ll := unpackBigint(buf)
|
||||||
@ -109,14 +110,14 @@ func unpackAddrContracts(buf []byte, addrDesc bchain.AddressDescriptor) (*AddrCo
|
|||||||
ac.Ids[i] = b
|
ac.Ids[i] = b
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ac.IdValues = make([]bchain.TokenTransferIdValue, len)
|
ac.MultiTokenValues = make([]bchain.MultiTokenValue, len)
|
||||||
for i := uint(0); i < len; i++ {
|
for i := uint(0); i < len; i++ {
|
||||||
b, ll := unpackBigint(buf)
|
b, ll := unpackBigint(buf)
|
||||||
buf = buf[ll:]
|
buf = buf[ll:]
|
||||||
ac.IdValues[i].Id = b
|
ac.MultiTokenValues[i].Id = b
|
||||||
b, ll = unpackBigint(buf)
|
b, ll = unpackBigint(buf)
|
||||||
buf = buf[ll:]
|
buf = buf[ll:]
|
||||||
ac.IdValues[i].Value = b
|
ac.MultiTokenValues[i].Value = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,9 +227,9 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
|
|||||||
s.Add(s, v)
|
s.Add(s, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if transfer.Type == bchain.ERC20 {
|
if transfer.Type == bchain.FungibleToken {
|
||||||
aggregate(&c.Value, &transfer.Value)
|
aggregate(&c.Value, &transfer.Value)
|
||||||
} else if transfer.Type == bchain.ERC721 {
|
} else if transfer.Type == bchain.NonFungibleToken {
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
// remove token from the list
|
// remove token from the list
|
||||||
for i := range c.Ids {
|
for i := range c.Ids {
|
||||||
@ -242,14 +243,14 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
|
|||||||
c.Ids = append(c.Ids, transfer.Value)
|
c.Ids = append(c.Ids, transfer.Value)
|
||||||
}
|
}
|
||||||
} else { // bchain.ERC1155
|
} else { // bchain.ERC1155
|
||||||
for _, t := range transfer.IdValues {
|
for _, t := range transfer.MultiTokenValues {
|
||||||
for i := range c.IdValues {
|
for i := range c.MultiTokenValues {
|
||||||
// find the token in the list
|
// find the token in the list
|
||||||
if c.IdValues[i].Id.Cmp(&t.Id) == 0 {
|
if c.MultiTokenValues[i].Id.Cmp(&t.Id) == 0 {
|
||||||
aggregate(&c.IdValues[i].Value, &t.Value)
|
aggregate(&c.MultiTokenValues[i].Value, &t.Value)
|
||||||
// if transfer from, remove if the value is zero
|
// if transfer from, remove if the value is zero
|
||||||
if index < 0 && len(c.IdValues[i].Value.Bits()) == 0 {
|
if index < 0 && len(c.MultiTokenValues[i].Value.Bits()) == 0 {
|
||||||
c.IdValues = append(c.IdValues[:i], c.IdValues[i+1:]...)
|
c.MultiTokenValues = append(c.MultiTokenValues[:i], c.MultiTokenValues[i+1:]...)
|
||||||
}
|
}
|
||||||
goto nextTransfer
|
goto nextTransfer
|
||||||
}
|
}
|
||||||
@ -257,7 +258,7 @@ func addToContract(c *AddrContract, contractIndex int, index int32, contract bch
|
|||||||
// if not found and transfer to, add to the list
|
// if not found and transfer to, add to the list
|
||||||
// it is necessary to add a copy of the value so that subsequent calls to addToContract do not change the transfer value
|
// it is necessary to add a copy of the value so that subsequent calls to addToContract do not change the transfer value
|
||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
c.IdValues = append(c.IdValues, bchain.TokenTransferIdValue{
|
c.MultiTokenValues = append(c.MultiTokenValues, bchain.MultiTokenValue{
|
||||||
Id: t.Id,
|
Id: t.Id,
|
||||||
Value: *new(big.Int).Set(&t.Value),
|
Value: *new(big.Int).Set(&t.Value),
|
||||||
})
|
})
|
||||||
@ -327,9 +328,9 @@ func (d *RocksDB) addToAddressesAndContractsEthereumType(addrDesc bchain.Address
|
|||||||
|
|
||||||
type ethBlockTxContract struct {
|
type ethBlockTxContract struct {
|
||||||
from, to, contract bchain.AddressDescriptor
|
from, to, contract bchain.AddressDescriptor
|
||||||
transferType bchain.TokenTransferType
|
transferType bchain.TokenType
|
||||||
value big.Int
|
value big.Int
|
||||||
idValues []bchain.TokenTransferIdValue
|
idValues []bchain.MultiTokenValue
|
||||||
}
|
}
|
||||||
|
|
||||||
type ethInternalTransfer struct {
|
type ethInternalTransfer struct {
|
||||||
@ -476,7 +477,7 @@ func (d *RocksDB) processContractTransfers(blockTx *ethBlockTx, tx *bchain.Tx, a
|
|||||||
bc.to = to
|
bc.to = to
|
||||||
bc.contract = contract
|
bc.contract = contract
|
||||||
bc.value = t.Value
|
bc.value = t.Value
|
||||||
bc.idValues = t.IdValues
|
bc.idValues = t.MultiTokenValues
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -699,6 +700,113 @@ func (d *RocksDB) storeInternalDataEthereumType(wb *gorocksdb.WriteBatch, blockT
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cachedContracts = make(map[string]*bchain.ContractInfo)
|
||||||
|
var cachedContractsMux sync.Mutex
|
||||||
|
|
||||||
|
func packContractInfo(contractInfo *bchain.ContractInfo) []byte {
|
||||||
|
buf := packString(contractInfo.Name)
|
||||||
|
buf = append(buf, packString(contractInfo.Symbol)...)
|
||||||
|
buf = append(buf, packString(string(contractInfo.Type))...)
|
||||||
|
varBuf := make([]byte, vlq.MaxLen64)
|
||||||
|
l := packVaruint(uint(contractInfo.Decimals), varBuf)
|
||||||
|
buf = append(buf, varBuf[:l]...)
|
||||||
|
l = packVaruint(uint(contractInfo.CreatedInBlock), varBuf)
|
||||||
|
buf = append(buf, varBuf[:l]...)
|
||||||
|
l = packVaruint(uint(contractInfo.DestructedInBlock), varBuf)
|
||||||
|
buf = append(buf, varBuf[:l]...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpackContractInfo(buf []byte) (*bchain.ContractInfo, error) {
|
||||||
|
var contractInfo bchain.ContractInfo
|
||||||
|
var s string
|
||||||
|
var l int
|
||||||
|
var ui uint
|
||||||
|
contractInfo.Name, l = unpackString(buf)
|
||||||
|
buf = buf[l:]
|
||||||
|
contractInfo.Symbol, l = unpackString(buf)
|
||||||
|
buf = buf[l:]
|
||||||
|
s, l = unpackString(buf)
|
||||||
|
contractInfo.Type = bchain.TokenTypeName(s)
|
||||||
|
buf = buf[l:]
|
||||||
|
ui, l = unpackVaruint(buf)
|
||||||
|
contractInfo.Decimals = int(ui)
|
||||||
|
buf = buf[l:]
|
||||||
|
ui, l = unpackVaruint(buf)
|
||||||
|
contractInfo.CreatedInBlock = uint32(ui)
|
||||||
|
buf = buf[l:]
|
||||||
|
ui, l = unpackVaruint(buf)
|
||||||
|
contractInfo.DestructedInBlock = uint32(ui)
|
||||||
|
return &contractInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *RocksDB) GetContractInfoForAddress(address string) (*bchain.ContractInfo, error) {
|
||||||
|
contract, err := d.chainParser.GetAddrDescFromAddress(address)
|
||||||
|
if err != nil || contract == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.GetContractInfo(contract, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContractInfo gets contract from cache or DB and possibly updates the type from typeFromContext
|
||||||
|
// this is because it is hard to guess the type of the contract using API, it is easier to set it the first time its usage is detected in tx
|
||||||
|
func (d *RocksDB) GetContractInfo(contract bchain.AddressDescriptor, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, error) {
|
||||||
|
cacheKey := string(contract)
|
||||||
|
cachedContractsMux.Lock()
|
||||||
|
contractInfo, found := cachedContracts[cacheKey]
|
||||||
|
cachedContractsMux.Unlock()
|
||||||
|
if !found {
|
||||||
|
val, err := d.db.GetCF(d.ro, d.cfh[cfContracts], contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer val.Free()
|
||||||
|
buf := val.Data()
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
contractInfo, err = unpackContractInfo(buf)
|
||||||
|
addresses, _, _ := d.chainParser.GetAddressesFromAddrDesc(contract)
|
||||||
|
if len(addresses) > 0 {
|
||||||
|
contractInfo.Contract = addresses[0]
|
||||||
|
}
|
||||||
|
// if the type is specified and stored contractInfo has unknown type, set and store it
|
||||||
|
if typeFromContext != bchain.UnknownTokenType && contractInfo.Type == bchain.UnknownTokenType {
|
||||||
|
contractInfo.Type = typeFromContext
|
||||||
|
err = d.db.PutCF(d.wo, d.cfh[cfContracts], contract, packContractInfo(contractInfo))
|
||||||
|
}
|
||||||
|
cachedContractsMux.Lock()
|
||||||
|
cachedContracts[cacheKey] = contractInfo
|
||||||
|
cachedContractsMux.Unlock()
|
||||||
|
}
|
||||||
|
return contractInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreContractInfo stores contractInfo in DB
|
||||||
|
// if CreatedInBlock==0 and DestructedInBlock!=0, it is evaluated as a desctruction of a contract, the contract info is updated
|
||||||
|
// in all other cases the contractInfo overwrites previously stored data in DB (however it should not really happen as contract is created only once)
|
||||||
|
func (d *RocksDB) StoreContractInfo(wb *gorocksdb.WriteBatch, contractInfo *bchain.ContractInfo) error {
|
||||||
|
if contractInfo.Contract != "" {
|
||||||
|
key, err := d.chainParser.GetAddrDescFromAddress(contractInfo.Contract)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if contractInfo.CreatedInBlock == 0 && contractInfo.DestructedInBlock != 0 {
|
||||||
|
storedCI, err := d.GetContractInfo(key, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if storedCI == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
storedCI.DestructedInBlock = contractInfo.DestructedInBlock
|
||||||
|
contractInfo = storedCI
|
||||||
|
}
|
||||||
|
wb.PutCF(d.cfh[cfContracts], key, packContractInfo(contractInfo))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func packBlockTx(buf []byte, blockTx *ethBlockTx) []byte {
|
func packBlockTx(buf []byte, blockTx *ethBlockTx) []byte {
|
||||||
varBuf := make([]byte, maxPackedBigintBytes)
|
varBuf := make([]byte, maxPackedBigintBytes)
|
||||||
buf = append(buf, blockTx.btxID...)
|
buf = append(buf, blockTx.btxID...)
|
||||||
@ -715,7 +823,7 @@ func packBlockTx(buf []byte, blockTx *ethBlockTx) []byte {
|
|||||||
buf = appendAddress(buf, c.contract)
|
buf = appendAddress(buf, c.contract)
|
||||||
l = packVaruint(uint(c.transferType), varBuf)
|
l = packVaruint(uint(c.transferType), varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
if c.transferType == bchain.ERC1155 {
|
if c.transferType == bchain.MultiToken {
|
||||||
l = packVaruint(uint(len(c.idValues)), varBuf)
|
l = packVaruint(uint(len(c.idValues)), varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
for i := range c.idValues {
|
for i := range c.idValues {
|
||||||
@ -773,6 +881,11 @@ func (d *RocksDB) storeBlockSpecificDataEthereumType(wb *gorocksdb.WriteBatch, b
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i := range blockSpecificData.Contracts {
|
||||||
|
if err := d.StoreContractInfo(wb, &blockSpecificData.Contracts[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -823,12 +936,12 @@ func unpackBlockTx(buf []byte, pos int) (*ethBlockTx, int, error) {
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
cc, l = unpackVaruint(buf[pos:])
|
cc, l = unpackVaruint(buf[pos:])
|
||||||
c.transferType = bchain.TokenTransferType(cc)
|
c.transferType = bchain.TokenType(cc)
|
||||||
pos += l
|
pos += l
|
||||||
if c.transferType == bchain.ERC1155 {
|
if c.transferType == bchain.MultiToken {
|
||||||
cc, l = unpackVaruint(buf[pos:])
|
cc, l = unpackVaruint(buf[pos:])
|
||||||
pos += l
|
pos += l
|
||||||
c.idValues = make([]bchain.TokenTransferIdValue, cc)
|
c.idValues = make([]bchain.MultiTokenValue, cc)
|
||||||
for i := range c.idValues {
|
for i := range c.idValues {
|
||||||
c.idValues[i].Id, l = unpackBigint(buf[pos:])
|
c.idValues[i].Id, l = unpackBigint(buf[pos:])
|
||||||
pos += l
|
pos += l
|
||||||
@ -938,9 +1051,9 @@ func (d *RocksDB) disconnectAddress(btxID []byte, internal bool, addrDesc bchain
|
|||||||
index = transferTo
|
index = transferTo
|
||||||
}
|
}
|
||||||
addToContract(addrContract, contractIndex, index, btxContract.contract, &bchain.TokenTransfer{
|
addToContract(addrContract, contractIndex, index, btxContract.contract, &bchain.TokenTransfer{
|
||||||
Type: btxContract.transferType,
|
Type: btxContract.transferType,
|
||||||
Value: btxContract.value,
|
Value: btxContract.value,
|
||||||
IdValues: btxContract.idValues,
|
MultiTokenValues: btxContract.idValues,
|
||||||
}, false)
|
}, false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -58,11 +58,11 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
|||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "020102", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "020102", nil},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
|
||||||
"020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"), nil,
|
"020100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
|
||||||
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintToHex(big.NewInt(0)), nil,
|
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintToHex(big.NewInt(0)), nil,
|
||||||
},
|
},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010002", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "010002", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010101", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "010101", nil},
|
||||||
@ -72,6 +72,25 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var destructedInBlock uint
|
||||||
|
if afterDisconnect {
|
||||||
|
destructedInBlock = 44445
|
||||||
|
}
|
||||||
|
if err := checkColumn(d, cfContracts, []keyPair{
|
||||||
|
{
|
||||||
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
|
||||||
|
"0b436f6e7472616374203734" + // Contract 74
|
||||||
|
"03533734" + // S74
|
||||||
|
"054552433230" + // ERC20
|
||||||
|
varuintToHex(12) + varuintToHex(44444) + varuintToHex(destructedInBlock),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
{
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := checkColumn(d, cfInternalData, []keyPair{
|
if err := checkColumn(d, cfInternalData, []keyPair{
|
||||||
{
|
{
|
||||||
dbtestdata.EthTxidB1T2,
|
dbtestdata.EthTxidB1T2,
|
||||||
@ -98,7 +117,7 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo
|
|||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" +
|
||||||
dbtestdata.EthTxidB1T2 +
|
dbtestdata.EthTxidB1T2 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) +
|
||||||
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"),
|
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"),
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -158,43 +177,43 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
|
|||||||
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
if err := checkColumn(d, cfAddressContracts, []keyPair{
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser),
|
||||||
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintToHex(big.NewInt(0)), nil,
|
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintToHex(big.NewInt(0)), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser),
|
||||||
"030202" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(1) + bigintFromStringToHex("150") + bigintFromStringToHex("1"), nil,
|
"030202" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(1) + bigintFromStringToHex("150") + bigintFromStringToHex("1"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser),
|
||||||
"010101" +
|
"010101" +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("8086") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("8086") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("871180000950184"), nil,
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("871180000950184"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser),
|
||||||
"050300" +
|
"050300" +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.ERC20)) + bigintFromStringToHex("10000000854307892726464") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(2<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000854307892726464") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0"), nil,
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser),
|
||||||
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(2) + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10"), nil,
|
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(2) + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser),
|
||||||
"020000" +
|
"020000" +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("0") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("0") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC20)) + bigintFromStringToHex("7674999999999991915") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(1<<2+uint(bchain.FungibleToken)) + bigintFromStringToHex("7674999999999991915") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC721)) + varuintToHex(1) + bigintFromStringToHex("1"), nil,
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.NonFungibleToken)) + varuintToHex(1) + bigintFromStringToHex("1"), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser),
|
||||||
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC721)) + varuintToHex(0), nil,
|
"010100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(1<<2+uint(bchain.NonFungibleToken)) + varuintToHex(0), nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser),
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser),
|
||||||
"010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.ERC1155)) + varuintToHex(0), nil,
|
"010000" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(1<<2+uint(bchain.MultiToken)) + varuintToHex(0), nil,
|
||||||
},
|
},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser), "010100", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser), "010100", nil},
|
||||||
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "030104", nil},
|
{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "030104", nil},
|
||||||
@ -209,6 +228,21 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := checkColumn(d, cfContracts, []keyPair{
|
||||||
|
{
|
||||||
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser),
|
||||||
|
"0b436f6e7472616374203734" + // Contract 74
|
||||||
|
"03533734" + // S74
|
||||||
|
"054552433230" + // ERC20
|
||||||
|
varuintToHex(12) + varuintToHex(44444) + varuintToHex(44445),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
{
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := checkColumn(d, cfInternalData, []keyPair{
|
if err := checkColumn(d, cfInternalData, []keyPair{
|
||||||
{
|
{
|
||||||
dbtestdata.EthTxidB1T2,
|
dbtestdata.EthTxidB1T2,
|
||||||
@ -243,22 +277,22 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
|
|||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" +
|
||||||
dbtestdata.EthTxidB2T2 +
|
dbtestdata.EthTxidB2T2 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser) +
|
||||||
"04" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("7675000000000000001") +
|
"04" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("7675000000000000001") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("854307892726464") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("854307892726464") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("871180000950184") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("871180000950184") +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("7674999999999991915") +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("7674999999999991915") +
|
||||||
dbtestdata.EthTxidB2T3 +
|
dbtestdata.EthTxidB2T3 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) +
|
||||||
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(uint(bchain.ERC721)) + bigintFromStringToHex("1") +
|
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr83, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContractCd, d.chainParser) + varuintToHex(uint(bchain.NonFungibleToken)) + bigintFromStringToHex("1") +
|
||||||
dbtestdata.EthTxidB2T4 +
|
dbtestdata.EthTxidB2T4 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr92, d.chainParser) +
|
||||||
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.ERC1155)) + "01" + bigintFromStringToHex("150") + bigintFromStringToHex("1") +
|
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrA3, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.MultiToken)) + "01" + bigintFromStringToHex("150") + bigintFromStringToHex("1") +
|
||||||
dbtestdata.EthTxidB2T5 +
|
dbtestdata.EthTxidB2T5 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) +
|
||||||
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrZero, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.ERC1155)) + "02" + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10") +
|
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrZero, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr5d, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract6f, d.chainParser) + varuintToHex(uint(bchain.MultiToken)) + "02" + bigintFromStringToHex("1776") + bigintFromStringToHex("1") + bigintFromStringToHex("1898") + bigintFromStringToHex("10") +
|
||||||
dbtestdata.EthTxidB2T6 +
|
dbtestdata.EthTxidB2T6 +
|
||||||
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) +
|
dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) +
|
||||||
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(uint(bchain.ERC20)) + bigintFromStringToHex("10000000000000000000000"),
|
"01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + varuintToHex(uint(bchain.FungibleToken)) + bigintFromStringToHex("10000000000000000000000"),
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -722,13 +756,13 @@ func Test_packUnpackAddrContracts(t *testing.T) {
|
|||||||
InternalTxs: 8873,
|
InternalTxs: 8873,
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract0d, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract0d, parser),
|
||||||
Txs: 8,
|
Txs: 8,
|
||||||
Value: *big.NewInt(793201132),
|
Value: *big.NewInt(793201132),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Txs: 41235,
|
Txs: 41235,
|
||||||
Ids: []big.Int{
|
Ids: []big.Int{
|
||||||
@ -740,10 +774,10 @@ func Test_packUnpackAddrContracts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
||||||
Txs: 64,
|
Txs: 64,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(1),
|
Id: *big.NewInt(1),
|
||||||
Value: *big.NewInt(1412341234),
|
Value: *big.NewInt(1412341234),
|
||||||
@ -796,7 +830,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: 1,
|
index: 1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Value: *big.NewInt(123456),
|
Value: *big.NewInt(123456),
|
||||||
},
|
},
|
||||||
addTxCount: true,
|
addTxCount: true,
|
||||||
@ -805,7 +839,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Txs: 1,
|
Txs: 1,
|
||||||
Value: *big.NewInt(123456),
|
Value: *big.NewInt(123456),
|
||||||
@ -819,7 +853,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: ^1,
|
index: ^1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Value: *big.NewInt(23456),
|
Value: *big.NewInt(23456),
|
||||||
},
|
},
|
||||||
addTxCount: true,
|
addTxCount: true,
|
||||||
@ -828,7 +862,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
@ -842,7 +876,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: 1,
|
index: 1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Value: *big.NewInt(1),
|
Value: *big.NewInt(1),
|
||||||
},
|
},
|
||||||
addTxCount: true,
|
addTxCount: true,
|
||||||
@ -851,13 +885,13 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 1,
|
Txs: 1,
|
||||||
Ids: []big.Int{*big.NewInt(1)},
|
Ids: []big.Int{*big.NewInt(1)},
|
||||||
@ -871,7 +905,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: 1,
|
index: 1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Value: *big.NewInt(2),
|
Value: *big.NewInt(2),
|
||||||
},
|
},
|
||||||
addTxCount: true,
|
addTxCount: true,
|
||||||
@ -880,13 +914,13 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
Ids: []big.Int{*big.NewInt(1), *big.NewInt(2)},
|
Ids: []big.Int{*big.NewInt(1), *big.NewInt(2)},
|
||||||
@ -900,7 +934,7 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: ^1,
|
index: ^1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Value: *big.NewInt(1),
|
Value: *big.NewInt(1),
|
||||||
},
|
},
|
||||||
addTxCount: false,
|
addTxCount: false,
|
||||||
@ -909,13 +943,13 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
Ids: []big.Int{*big.NewInt(2)},
|
Ids: []big.Int{*big.NewInt(2)},
|
||||||
@ -929,8 +963,8 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: 1,
|
index: 1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(56789),
|
Value: *big.NewInt(56789),
|
||||||
@ -943,22 +977,22 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
Ids: []big.Int{*big.NewInt(2)},
|
Ids: []big.Int{*big.NewInt(2)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
Txs: 1,
|
Txs: 1,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(56789),
|
Value: *big.NewInt(56789),
|
||||||
@ -974,8 +1008,8 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: 1,
|
index: 1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(111),
|
Value: *big.NewInt(111),
|
||||||
@ -992,22 +1026,22 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
Ids: []big.Int{*big.NewInt(2)},
|
Ids: []big.Int{*big.NewInt(2)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(56900),
|
Value: *big.NewInt(56900),
|
||||||
@ -1027,8 +1061,8 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
index: ^1,
|
index: ^1,
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
transfer: &bchain.TokenTransfer{
|
transfer: &bchain.TokenTransfer{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(112),
|
Value: *big.NewInt(112),
|
||||||
@ -1045,22 +1079,22 @@ func Test_addToContracts(t *testing.T) {
|
|||||||
wantAddrContracts: &AddrContracts{
|
wantAddrContracts: &AddrContracts{
|
||||||
Contracts: []AddrContract{
|
Contracts: []AddrContract{
|
||||||
{
|
{
|
||||||
Type: bchain.ERC20,
|
Type: bchain.FungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract47, parser),
|
||||||
Value: *big.NewInt(100000),
|
Value: *big.NewInt(100000),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC721,
|
Type: bchain.NonFungibleToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
Txs: 2,
|
Txs: 2,
|
||||||
Ids: []big.Int{*big.NewInt(2)},
|
Ids: []big.Int{*big.NewInt(2)},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: bchain.ERC1155,
|
Type: bchain.MultiToken,
|
||||||
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
Contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
Txs: 3,
|
Txs: 3,
|
||||||
IdValues: []bchain.TokenTransferIdValue{
|
MultiTokenValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(11),
|
Id: *big.NewInt(11),
|
||||||
Value: *big.NewInt(56788),
|
Value: *big.NewInt(56788),
|
||||||
@ -1119,7 +1153,7 @@ func Test_packUnpackBlockTx(t *testing.T) {
|
|||||||
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
|
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
|
||||||
to: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
|
to: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
||||||
transferType: bchain.ERC20,
|
transferType: bchain.FungibleToken,
|
||||||
value: *big.NewInt(10000),
|
value: *big.NewInt(10000),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1137,22 +1171,22 @@ func Test_packUnpackBlockTx(t *testing.T) {
|
|||||||
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
|
from: addressToAddrDesc(dbtestdata.EthAddr20, parser),
|
||||||
to: addressToAddrDesc(dbtestdata.EthAddr3e, parser),
|
to: addressToAddrDesc(dbtestdata.EthAddr3e, parser),
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract4a, parser),
|
||||||
transferType: bchain.ERC20,
|
transferType: bchain.FungibleToken,
|
||||||
value: *big.NewInt(987654321),
|
value: *big.NewInt(987654321),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: addressToAddrDesc(dbtestdata.EthAddr4b, parser),
|
from: addressToAddrDesc(dbtestdata.EthAddr4b, parser),
|
||||||
to: addressToAddrDesc(dbtestdata.EthAddr55, parser),
|
to: addressToAddrDesc(dbtestdata.EthAddr55, parser),
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContract6f, parser),
|
||||||
transferType: bchain.ERC721,
|
transferType: bchain.NonFungibleToken,
|
||||||
value: *big.NewInt(13),
|
value: *big.NewInt(13),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
from: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
|
from: addressToAddrDesc(dbtestdata.EthAddr5d, parser),
|
||||||
to: addressToAddrDesc(dbtestdata.EthAddr7b, parser),
|
to: addressToAddrDesc(dbtestdata.EthAddr7b, parser),
|
||||||
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
contract: addressToAddrDesc(dbtestdata.EthAddrContractCd, parser),
|
||||||
transferType: bchain.ERC1155,
|
transferType: bchain.MultiToken,
|
||||||
idValues: []bchain.TokenTransferIdValue{
|
idValues: []bchain.MultiTokenValue{
|
||||||
{
|
{
|
||||||
Id: *big.NewInt(1234),
|
Id: *big.NewInt(1234),
|
||||||
Value: *big.NewInt(98765),
|
Value: *big.NewInt(98765),
|
||||||
@ -1222,3 +1256,45 @@ func Test_packUnpackFourByteSignature(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_packUnpackContractInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
contractInfo bchain.ContractInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
contractInfo: bchain.ContractInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown",
|
||||||
|
contractInfo: bchain.ContractInfo{
|
||||||
|
Type: bchain.UnknownTokenType,
|
||||||
|
Name: "Test contract",
|
||||||
|
Symbol: "TCT",
|
||||||
|
Decimals: 18,
|
||||||
|
CreatedInBlock: 1234567,
|
||||||
|
DestructedInBlock: 234567890,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERC20",
|
||||||
|
contractInfo: bchain.ContractInfo{
|
||||||
|
Type: bchain.ERC20TokenType,
|
||||||
|
Name: "GreenContract🟢",
|
||||||
|
Symbol: "🟢",
|
||||||
|
Decimals: 0,
|
||||||
|
CreatedInBlock: 1,
|
||||||
|
DestructedInBlock: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
buf := packContractInfo(&tt.contractInfo)
|
||||||
|
if got, err := unpackContractInfo(buf); !reflect.DeepEqual(*got, tt.contractInfo) || err != nil {
|
||||||
|
t.Errorf("packUnpackContractInfo() = %v, want %v, error %v", *got, tt.contractInfo, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -562,7 +562,7 @@ func isOwnAddress(td *TemplateData, a string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called from template, returns count of token transfers of given type in a tx
|
// called from template, returns count of token transfers of given type in a tx
|
||||||
func tokenTransfersCount(tx *api.Tx, t api.TokenType) int {
|
func tokenTransfersCount(tx *api.Tx, t bchain.TokenTypeName) int {
|
||||||
count := 0
|
count := 0
|
||||||
for i := range tx.TokenTransfers {
|
for i := range tx.TokenTransfers {
|
||||||
if tx.TokenTransfers[i].Type == t {
|
if tx.TokenTransfers[i].Type == t {
|
||||||
@ -573,7 +573,7 @@ func tokenTransfersCount(tx *api.Tx, t api.TokenType) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called from template, returns count of tokens in array of given type
|
// called from template, returns count of tokens in array of given type
|
||||||
func tokenCount(tokens []api.Token, t api.TokenType) int {
|
func tokenCount(tokens []api.Token, t bchain.TokenTypeName) int {
|
||||||
count := 0
|
count := 0
|
||||||
for i := range tokens {
|
for i := range tokens {
|
||||||
if tokens[i].Type == t {
|
if tokens[i].Type == t {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -896,7 +896,7 @@ func (s *WebsocketServer) sendOnNewTxAddr(stringAddressDescriptor string, tx *ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *WebsocketServer) getNewTxSubscriptions(tx *bchain.MempoolTx) map[string]struct{} {
|
func (s *WebsocketServer) getNewTxSubscriptions(tx *bchain.MempoolTx) map[string]struct{} {
|
||||||
// check if there is any subscription in inputs, outputs and erc20
|
// check if there is any subscription in inputs, outputs and token transfers
|
||||||
s.addressSubscriptionsLock.Lock()
|
s.addressSubscriptionsLock.Lock()
|
||||||
defer s.addressSubscriptionsLock.Unlock()
|
defer s.addressSubscriptionsLock.Unlock()
|
||||||
subscribed := make(map[string]struct{})
|
subscribed := make(map[string]struct{})
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
|
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
|
||||||
<h1>{{if $addr.Erc20Contract}}Contract {{$addr.Erc20Contract.Name}} ({{$addr.Erc20Contract.Symbol}}){{else}}Address{{end}} <small class="text-muted">{{formatAmount $addr.BalanceSat}} {{$cs}}</small>
|
<h1>{{if $addr.ContractInfo}}Contract {{$addr.ContractInfo.Name}} ({{$addr.ContractInfo.Symbol}}){{else}}Address{{end}} <small class="text-muted">{{formatAmount $addr.BalanceSat}} {{$cs}}</small>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="alert alert-data ellipsis">
|
<div class="alert alert-data ellipsis">
|
||||||
<span class="data">{{$addr.AddrStr}}</span>
|
<span class="data">{{$addr.AddrStr}}</span>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="data ellipsis">{{if $t.Contract}}<a href="/address/{{$t.Contract}}">{{$t.Name}}</a>{{else}}{{$t.Name}}{{end}}</td>
|
<td class="data ellipsis">{{if $t.Contract}}<a href="/address/{{$t.Contract}}">{{$t.Name}}</a>{{else}}{{$t.Name}}{{end}}</td>
|
||||||
<td class="data">
|
<td class="data">
|
||||||
{{range $i, $iv := $t.IdValues}}{{if $i}}, {{end}}{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$t.Symbol}}{{end}}
|
{{range $i, $iv := $t.MultiTokenValues}}{{if $i}}, {{end}}{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$t.Symbol}}{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="data">{{$t.Transfers}}</td>
|
<td class="data">{{$t.Transfers}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -267,7 +267,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 text-right" style="padding: .4rem 0;">
|
<div class="col-md-3 text-right" style="padding: .4rem 0;">
|
||||||
{{- range $iv := $tt.Values -}}
|
{{- range $iv := $tt.MultiTokenValues -}}
|
||||||
{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$tt.Symbol}}
|
{{formatAmountWithDecimals $iv.Id 0}}:{{formatAmountWithDecimals $iv.Value 0}} {{$tt.Symbol}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -128,6 +128,19 @@ var EthTx4InternalData = &bchain.EthereumInternalData{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Block1SpecificData = &bchain.EthereumBlockSpecificData{
|
||||||
|
Contracts: []bchain.ContractInfo{
|
||||||
|
{
|
||||||
|
Contract: EthAddrContract4a,
|
||||||
|
Type: bchain.ERC20TokenType,
|
||||||
|
Name: "Contract 74",
|
||||||
|
Symbol: "S74",
|
||||||
|
Decimals: 12,
|
||||||
|
CreatedInBlock: 44444,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var Block2SpecificData = &bchain.EthereumBlockSpecificData{
|
var Block2SpecificData = &bchain.EthereumBlockSpecificData{
|
||||||
InternalDataError: "test error",
|
InternalDataError: "test error",
|
||||||
AddressAliasRecords: []bchain.AddressAliasRecord{
|
AddressAliasRecords: []bchain.AddressAliasRecord{
|
||||||
@ -140,6 +153,12 @@ var Block2SpecificData = &bchain.EthereumBlockSpecificData{
|
|||||||
Name: "address20",
|
Name: "address20",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Contracts: []bchain.ContractInfo{
|
||||||
|
{
|
||||||
|
Contract: EthAddrContract4a,
|
||||||
|
DestructedInBlock: 44445,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type packedAndInternal struct {
|
type packedAndInternal struct {
|
||||||
@ -182,6 +201,7 @@ func GetTestEthereumTypeBlock1(parser bchain.BlockChainParser) *bchain.Block {
|
|||||||
packed: EthTx2Packed,
|
packed: EthTx2Packed,
|
||||||
internal: EthTx2InternalData,
|
internal: EthTx2InternalData,
|
||||||
}}, parser),
|
}}, parser),
|
||||||
|
CoinSpecificData: Block1SpecificData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -117,13 +117,15 @@ func (c *fakeBlockChainEthereumType) EthereumTypeGetNonce(addrDesc bchain.Addres
|
|||||||
return uint64(addrDesc[0]), nil
|
return uint64(addrDesc[0]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChainEthereumType) EthereumTypeGetErc20ContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.Erc20Contract, error) {
|
func (c *fakeBlockChainEthereumType) GetContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.ContractInfo, error) {
|
||||||
addresses, _, _ := c.Parser.GetAddressesFromAddrDesc(contractDesc)
|
addresses, _, _ := c.Parser.GetAddressesFromAddrDesc(contractDesc)
|
||||||
return &bchain.Erc20Contract{
|
return &bchain.ContractInfo{
|
||||||
Contract: addresses[0],
|
Type: bchain.ERC20TokenType,
|
||||||
Name: "Contract " + strconv.Itoa(int(contractDesc[0])),
|
Contract: addresses[0],
|
||||||
Symbol: "S" + strconv.Itoa(int(contractDesc[0])),
|
Name: "Contract " + strconv.Itoa(int(contractDesc[0])),
|
||||||
Decimals: 18,
|
Symbol: "S" + strconv.Itoa(int(contractDesc[0])),
|
||||||
|
Decimals: 18,
|
||||||
|
CreatedInBlock: 12345,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user