Process ETH transaction failure reasons
This commit is contained in:
parent
91031715f7
commit
45a53e41a1
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
@ -88,7 +89,7 @@ func (p *EthereumParser) ethTxToTx(tx *bchain.RpcTransaction, receipt *bchain.Rp
|
|||||||
}
|
}
|
||||||
if internalData != nil {
|
if internalData != nil {
|
||||||
// ignore empty internal data
|
// ignore empty internal data
|
||||||
if internalData.Type == bchain.CALL && len(internalData.Transfers) == 0 {
|
if internalData.Type == bchain.CALL && len(internalData.Transfers) == 0 && len(internalData.Error) == 0 {
|
||||||
internalData = nil
|
internalData = nil
|
||||||
} else {
|
} else {
|
||||||
if fixEIP55 {
|
if fixEIP55 {
|
||||||
@ -505,3 +506,45 @@ func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTx
|
|||||||
}
|
}
|
||||||
return &etd
|
return &etd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const errorOutputSignature = "08c379a0"
|
||||||
|
|
||||||
|
// ParseErrorFromOutput takes output field from internal transaction data and extracts an error message from it
|
||||||
|
// the output must have errorOutputSignature to be parsed
|
||||||
|
func ParseErrorFromOutput(output string) string {
|
||||||
|
if has0xPrefix(output) {
|
||||||
|
output = output[2:]
|
||||||
|
}
|
||||||
|
if len(output) < 8+64+64+64 || output[:8] != errorOutputSignature {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return parseErc20StringProperty(nil, output[8:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// PackInternalTransactionError packs common error messages to single byte to save DB space
|
||||||
|
func PackInternalTransactionError(e string) string {
|
||||||
|
if e == "execution reverted" {
|
||||||
|
return "\x01"
|
||||||
|
}
|
||||||
|
if e == "out of gas" {
|
||||||
|
return "\x02"
|
||||||
|
}
|
||||||
|
if e == "contract creation code storage out of gas" {
|
||||||
|
return "\x03"
|
||||||
|
}
|
||||||
|
if e == "max code size exceeded" {
|
||||||
|
return "\x04"
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpackInternalTransactionError unpacks common error messages packed by PackInternalTransactionError
|
||||||
|
func UnpackInternalTransactionError(data []byte) string {
|
||||||
|
e := string(data)
|
||||||
|
e = strings.ReplaceAll(e, "\x01", "Reverted. ")
|
||||||
|
e = strings.ReplaceAll(e, "\x02", "Out of gas. ")
|
||||||
|
e = strings.ReplaceAll(e, "\x03", "Contract creation code storage out of gas. ")
|
||||||
|
e = strings.ReplaceAll(e, "\x04", "Max code size exceeded. ")
|
||||||
|
return strings.TrimSpace(e)
|
||||||
|
}
|
||||||
|
|||||||
@ -400,3 +400,97 @@ func TestEthereumParser_GetEthereumTxData(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEthereumParser_ParseErrorFromOutput(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
output string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ParseErrorFromOutput 1",
|
||||||
|
output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000031546f74616c206e756d626572206f662067726f757073206d7573742062652067726561746572207468616e207a65726f2e000000000000000000000000000000",
|
||||||
|
want: "Total number of groups must be greater than zero.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ParseErrorFromOutput 2",
|
||||||
|
output: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000",
|
||||||
|
want: "not enough balance",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ParseErrorFromOutput empty",
|
||||||
|
output: "",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ParseErrorFromOutput short",
|
||||||
|
output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ParseErrorFromOutput invalid signature",
|
||||||
|
output: "0x08c379b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := ParseErrorFromOutput(tt.output)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("EthereumParser.ParseErrorFromOutput() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthereumParser_PackInternalTransactionError_UnpackInternalTransactionError(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
original string
|
||||||
|
packed string
|
||||||
|
unpacked string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "execution reverted",
|
||||||
|
original: "execution reverted",
|
||||||
|
packed: "\x01",
|
||||||
|
unpacked: "Reverted.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "out of gas",
|
||||||
|
original: "out of gas",
|
||||||
|
packed: "\x02",
|
||||||
|
unpacked: "Out of gas.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "contract creation code storage out of gas",
|
||||||
|
original: "contract creation code storage out of gas",
|
||||||
|
packed: "\x03",
|
||||||
|
unpacked: "Contract creation code storage out of gas.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "max code size exceeded",
|
||||||
|
original: "max code size exceeded",
|
||||||
|
packed: "\x04",
|
||||||
|
unpacked: "Max code size exceeded.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown error",
|
||||||
|
original: "unknown error",
|
||||||
|
packed: "unknown error",
|
||||||
|
unpacked: "unknown error",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
packed := PackInternalTransactionError(tt.original)
|
||||||
|
if packed != tt.packed {
|
||||||
|
t.Errorf("EthereumParser.PackInternalTransactionError() = %v, want %v", packed, tt.packed)
|
||||||
|
}
|
||||||
|
unpacked := UnpackInternalTransactionError([]byte(packed))
|
||||||
|
if unpacked != tt.unpacked {
|
||||||
|
t.Errorf("EthereumParser.UnpackInternalTransactionError() = %v, want %v", unpacked, tt.unpacked)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -512,19 +513,20 @@ func (b *EthereumRPC) getERC20EventsForBlock(blockNumber string) (map[string][]*
|
|||||||
|
|
||||||
type rpcCallTrace struct {
|
type rpcCallTrace struct {
|
||||||
// CREATE, CREATE2, SELFDESTRUCT, CALL, CALLCODE, DELEGATECALL, STATICCALL
|
// CREATE, CREATE2, SELFDESTRUCT, CALL, CALLCODE, DELEGATECALL, STATICCALL
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
Calls []rpcCallTrace `json:"calls"`
|
Output string `json:"output"`
|
||||||
|
Calls []rpcCallTrace `json:"calls"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcTraceResult struct {
|
type rpcTraceResult struct {
|
||||||
Result rpcCallTrace `json:"result"`
|
Result rpcCallTrace `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) processCallTrace(call rpcCallTrace, d *bchain.EthereumInternalData) {
|
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData) {
|
||||||
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{
|
||||||
@ -548,8 +550,11 @@ func (b *EthereumRPC) processCallTrace(call rpcCallTrace, d *bchain.EthereumInte
|
|||||||
To: call.To,
|
To: call.To,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if call.Error != "" {
|
||||||
|
d.Error = call.Error
|
||||||
|
}
|
||||||
for i := range call.Calls {
|
for i := range call.Calls {
|
||||||
b.processCallTrace(call.Calls[i], d)
|
b.processCallTrace(&call.Calls[i], d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,7 +584,28 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, transactions []b
|
|||||||
d.Type = bchain.SELFDESTRUCT
|
d.Type = bchain.SELFDESTRUCT
|
||||||
}
|
}
|
||||||
for j := range r.Calls {
|
for j := range r.Calls {
|
||||||
b.processCallTrace(r.Calls[j], d)
|
b.processCallTrace(&r.Calls[j], d)
|
||||||
|
}
|
||||||
|
if r.Error != "" {
|
||||||
|
baseError := PackInternalTransactionError(r.Error)
|
||||||
|
if len(baseError) > 1 {
|
||||||
|
// n, _ := ethNumber(transactions[i].BlockNumber)
|
||||||
|
// glog.Infof("Internal Data Error %d %s: unknown base error %s", n, transactions[i].Hash, baseError)
|
||||||
|
baseError = strings.ToUpper(baseError[:1]) + baseError[1:] + ". "
|
||||||
|
}
|
||||||
|
outputError := ParseErrorFromOutput(r.Output)
|
||||||
|
if len(outputError) > 0 {
|
||||||
|
d.Error = baseError + strings.ToUpper(outputError[:1]) + outputError[1:]
|
||||||
|
} else {
|
||||||
|
traceError := PackInternalTransactionError(d.Error)
|
||||||
|
if traceError == baseError {
|
||||||
|
d.Error = baseError
|
||||||
|
} else {
|
||||||
|
d.Error = baseError + traceError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// n, _ := ethNumber(transactions[i].BlockNumber)
|
||||||
|
// glog.Infof("Internal Data Error %d %s: %s", n, transactions[i].Hash, UnpackInternalTransactionError([]byte(d.Error)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -719,7 +745,6 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
}
|
}
|
||||||
// TODO - handle internal tx
|
|
||||||
btx, err = b.Parser.ethTxToTx(tx, &receipt, nil, time, confirmations, true)
|
btx, err = b.Parser.ethTxToTx(tx, &receipt, nil, time, confirmations, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||||
|
|||||||
@ -27,6 +27,7 @@ type EthereumInternalData struct {
|
|||||||
Type EthereumInternalTransactionType `json:"type"`
|
Type EthereumInternalTransactionType `json:"type"`
|
||||||
Contract string `json:"contract,omitempty"`
|
Contract string `json:"contract,omitempty"`
|
||||||
Transfers []EthereumInternalTransfer `json:"transfers,omitempty"`
|
Transfers []EthereumInternalTransfer `json:"transfers,omitempty"`
|
||||||
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erc20Contract contains info about ERC20 contract
|
// Erc20Contract contains info about ERC20 contract
|
||||||
|
|||||||
@ -189,6 +189,7 @@ type ethInternalData struct {
|
|||||||
internalType bchain.EthereumInternalTransactionType
|
internalType bchain.EthereumInternalTransactionType
|
||||||
contract bchain.AddressDescriptor
|
contract bchain.AddressDescriptor
|
||||||
transfers []ethInternalTransfer
|
transfers []ethInternalTransfer
|
||||||
|
errorMsg string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ethBlockTx struct {
|
type ethBlockTx struct {
|
||||||
@ -242,6 +243,7 @@ func (d *RocksDB) processAddressesEthereumType(block *bchain.Block, addresses ad
|
|||||||
if eid.InternalData != nil {
|
if eid.InternalData != nil {
|
||||||
blockTx.internalData = ðInternalData{
|
blockTx.internalData = ðInternalData{
|
||||||
internalType: eid.InternalData.Type,
|
internalType: eid.InternalData.Type,
|
||||||
|
errorMsg: eid.InternalData.Error,
|
||||||
}
|
}
|
||||||
// index contract creation
|
// index contract creation
|
||||||
if eid.InternalData.Type == bchain.CREATE {
|
if eid.InternalData.Type == bchain.CREATE {
|
||||||
@ -365,6 +367,9 @@ func packEthInternalData(data *ethInternalData) []byte {
|
|||||||
l = packBigint(&t.value, varBuf)
|
l = packBigint(&t.value, varBuf)
|
||||||
buf = append(buf, varBuf[:l]...)
|
buf = append(buf, varBuf[:l]...)
|
||||||
}
|
}
|
||||||
|
if len(data.errorMsg) > 0 {
|
||||||
|
buf = append(buf, []byte(data.errorMsg)...)
|
||||||
|
}
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,6 +403,7 @@ func (d *RocksDB) unpackEthInternalData(buf []byte) (*bchain.EthereumInternalDat
|
|||||||
t.Value, ll = unpackBigint(buf[l:])
|
t.Value, ll = unpackBigint(buf[l:])
|
||||||
l += ll
|
l += ll
|
||||||
}
|
}
|
||||||
|
id.Error = eth.UnpackInternalTransactionError(buf[l:])
|
||||||
return &id, nil
|
return &id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +429,7 @@ func (d *RocksDB) storeInternalDataEthereumType(wb *gorocksdb.WriteBatch, blockT
|
|||||||
for i := range blockTxs {
|
for i := range blockTxs {
|
||||||
blockTx := &blockTxs[i]
|
blockTx := &blockTxs[i]
|
||||||
if blockTx.internalData != nil {
|
if blockTx.internalData != nil {
|
||||||
wb.PutCF(d.cfh[cfInternalData], blockTx.btxID, packEthInternalData(blockTx.internalData))
|
wb.PutCF(d.cfh[cfInternalData], blockTx.btxID, packEthInternalData(blockTx.internalData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -163,6 +163,11 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB, wantBlockInternalDa
|
|||||||
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr3e + "030f4242",
|
"00" + dbtestdata.EthAddr3e + dbtestdata.EthAddr3e + "030f4242",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
dbtestdata.EthTxidB2T1,
|
||||||
|
"00" + hex.EncodeToString([]byte(dbtestdata.EthTx3InternalData.Error)),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
dbtestdata.EthTxidB2T2,
|
dbtestdata.EthTxidB2T2,
|
||||||
"05" + dbtestdata.EthAddrContract0d +
|
"05" + dbtestdata.EthAddrContract0d +
|
||||||
@ -231,6 +236,7 @@ func formatInternalData(in *bchain.EthereumInternalData) *bchain.EthereumInterna
|
|||||||
t.From = eth.EIP55AddressFromAddress(t.From)
|
t.From = eth.EIP55AddressFromAddress(t.From)
|
||||||
t.To = eth.EIP55AddressFromAddress(t.To)
|
t.To = eth.EIP55AddressFromAddress(t.To)
|
||||||
}
|
}
|
||||||
|
out.Error = eth.UnpackInternalTransactionError([]byte(in.Error))
|
||||||
return &out
|
return &out
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +301,10 @@ func TestRocksDB_Index_EthereumType(t *testing.T) {
|
|||||||
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx2InternalData)) {
|
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx2InternalData)) {
|
||||||
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB1T2, id, formatInternalData(dbtestdata.EthTx2InternalData), err)
|
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB1T2, id, formatInternalData(dbtestdata.EthTx2InternalData), err)
|
||||||
}
|
}
|
||||||
|
id, err = d.GetEthereumInternalData(dbtestdata.EthTxidB2T1)
|
||||||
|
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx3InternalData)) {
|
||||||
|
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB2T1, id, formatInternalData(dbtestdata.EthTx3InternalData), err)
|
||||||
|
}
|
||||||
id, err = d.GetEthereumInternalData(dbtestdata.EthTxidB2T2)
|
id, err = d.GetEthereumInternalData(dbtestdata.EthTxidB2T2)
|
||||||
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx4InternalData)) {
|
if err != nil || !reflect.DeepEqual(id, formatInternalData(dbtestdata.EthTx4InternalData)) {
|
||||||
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB2T2, id, formatInternalData(dbtestdata.EthTx4InternalData), err)
|
t.Errorf("GetEthereumInternalData(%s) = %+v, want %+v, err %v", dbtestdata.EthTxidB2T2, id, formatInternalData(dbtestdata.EthTx4InternalData), err)
|
||||||
@ -348,7 +358,15 @@ func TestRocksDB_Index_EthereumType(t *testing.T) {
|
|||||||
|
|
||||||
// Test tx caching functionality, leave one tx in db to test cleanup in DisconnectBlock
|
// Test tx caching functionality, leave one tx in db to test cleanup in DisconnectBlock
|
||||||
testTxCache(t, d, block1, &block1.Txs[0])
|
testTxCache(t, d, block1, &block1.Txs[0])
|
||||||
|
// InternalData are not packed and stored in DB, remove them so that the test does not fail
|
||||||
|
esd, _ := block2.Txs[0].CoinSpecificData.(bchain.EthereumSpecificData)
|
||||||
|
eid := esd.InternalData
|
||||||
|
esd.InternalData = nil
|
||||||
|
block2.Txs[0].CoinSpecificData = esd
|
||||||
testTxCache(t, d, block2, &block2.Txs[0])
|
testTxCache(t, d, block2, &block2.Txs[0])
|
||||||
|
// restore InternalData
|
||||||
|
esd.InternalData = eid
|
||||||
|
block2.Txs[0].CoinSpecificData = esd
|
||||||
if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
|
if err = d.PutTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -515,7 +515,7 @@ func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) {
|
|||||||
// Confirmations are not stored in the DB, set them from input tx
|
// Confirmations are not stored in the DB, set them from input tx
|
||||||
gtx.Confirmations = tx.Confirmations
|
gtx.Confirmations = tx.Confirmations
|
||||||
if !reflect.DeepEqual(gtx, tx) {
|
if !reflect.DeepEqual(gtx, tx) {
|
||||||
t.Errorf("GetTx: %v, want %v", gtx, tx)
|
t.Errorf("GetTx: %+v, want %+v", gtx, tx)
|
||||||
}
|
}
|
||||||
if err := d.DeleteTx(tx.Txid); err != nil {
|
if err := d.DeleteTx(tx.Txid); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@ -54,6 +54,12 @@ var EthTx2InternalData = &bchain.EthereumInternalData{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var EthTx3InternalData = &bchain.EthereumInternalData{
|
||||||
|
Type: bchain.CALL,
|
||||||
|
Transfers: []bchain.EthereumInternalTransfer{},
|
||||||
|
Error: "\x01Something wrong",
|
||||||
|
}
|
||||||
|
|
||||||
var EthTx4InternalData = &bchain.EthereumInternalData{
|
var EthTx4InternalData = &bchain.EthereumInternalData{
|
||||||
Type: bchain.CREATE,
|
Type: bchain.CREATE,
|
||||||
Contract: EthAddrContract0d,
|
Contract: EthAddrContract0d,
|
||||||
@ -127,7 +133,8 @@ func GetTestEthereumTypeBlock2(parser bchain.BlockChainParser) *bchain.Block {
|
|||||||
Confirmations: 1,
|
Confirmations: 1,
|
||||||
},
|
},
|
||||||
Txs: unpackTxs([]packedAndInternal{{
|
Txs: unpackTxs([]packedAndInternal{{
|
||||||
packed: EthTx3Packed,
|
packed: EthTx3Packed,
|
||||||
|
internal: EthTx3InternalData,
|
||||||
}, {
|
}, {
|
||||||
packed: EthTx4Packed,
|
packed: EthTx4Packed,
|
||||||
internal: EthTx4InternalData,
|
internal: EthTx4InternalData,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user