new: add bor testcases

This commit is contained in:
Jaynti Kanani 2020-11-14 14:53:35 +05:30
parent 82246a5e94
commit 7fe2cd4384
No known key found for this signature in database
GPG key ID: 4396982C976BAE5E
7 changed files with 662 additions and 0 deletions

1
go.sum
View file

@ -200,6 +200,7 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

270
tests/bor/bor_test.go Normal file
View file

@ -0,0 +1,270 @@
package bor
import (
"encoding/hex"
"encoding/json"
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/ethereum/go-ethereum/consensus/bor"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/tests/bor/mocks"
)
var (
spanPath = "bor/span/1"
clerkPath = "clerk/event-record/list"
clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
)
func TestInsertingSpanSizeBlocks(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
h, heimdallSpan := getMockedHeimdallClient(t)
_bor.SetHeimdallClient(h)
db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db)
// to := int64(block.Header().Time)
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
for i := uint64(1); i <= spanSize; i++ {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
}
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
validators, err := _bor.GetCurrentValidators(sprintSize, spanSize) // check validator set at the first block of new span
if err != nil {
t.Fatalf("%s", err)
}
assert.Equal(t, 3, len(validators))
for i, validator := range validators {
assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
}
}
func TestFetchStateSyncEvents(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
// A. Insert blocks for 0th sprint
db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db)
// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
for i := uint64(1); i < sprintSize; i++ {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
}
// B. Before inserting 1st block of the next sprint, mock heimdall deps
// B.1 Mock /bor/span/1
res, _ := loadSpanFromFile(t)
h := &mocks.IHeimdallClient{}
h.On("FetchWithRetry", spanPath, "").Return(res, nil)
// B.2 Mock State Sync events
fromID := uint64(1)
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
to := int64(chain.GetHeaderByNumber(0).Time)
eventCount := 50
sample := getSampleEventRecord(t)
sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
eventRecords := generateFakeStateSyncEvents(sample, eventCount)
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
_bor.SetHeimdallClient(h)
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
}
func TestFetchStateSyncEvents_2(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
// Mock /bor/span/1
res, _ := loadSpanFromFile(t)
h := &mocks.IHeimdallClient{}
h.On("FetchWithRetry", spanPath, "").Return(res, nil)
// Mock State Sync events
// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
fromID := uint64(1)
to := int64(chain.GetHeaderByNumber(0).Time)
sample := getSampleEventRecord(t)
// First query will be from [id=1, (block-sprint).Time]
// Insert 5 events in this time range
eventRecords := []*bor.EventRecordWithTime{
buildStateEvent(sample, 1, 3), // id = 1, time = 1
buildStateEvent(sample, 2, 1), // id = 2, time = 3
buildStateEvent(sample, 3, 2), // id = 3, time = 2
// event with id 5 is missing
buildStateEvent(sample, 4, 5), // id = 4, time = 5
buildStateEvent(sample, 6, 4), // id = 6, time = 4
}
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
_bor.SetHeimdallClient(h)
// Insert blocks for 0th sprint
db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db)
for i := uint64(1); i <= sprintSize; i++ {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
}
assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
// state 6 was not written
assert.Equal(t, uint64(4), lastStateID.Uint64())
//
fromID = uint64(5)
to = int64(chain.GetHeaderByNumber(sprintSize).Time)
eventRecords = []*bor.EventRecordWithTime{
buildStateEvent(sample, 5, 7),
buildStateEvent(sample, 6, 4),
}
h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
for i := sprintSize + 1; i <= spanSize; i++ {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
}
assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
assert.Equal(t, uint64(6), lastStateID.Uint64())
}
func TestOutOfTurnSigning(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
h, _ := getMockedHeimdallClient(t)
_bor.SetHeimdallClient(h)
db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db)
for i := uint64(1); i < spanSize; i++ {
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
insertNewBlock(t, chain, block)
}
// insert spanSize-th block
// This account is one the out-of-turn validators for 1st (0-indexed) span
signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
signerKey, _ := hex.DecodeString(signer)
key, _ = crypto.HexToECDSA(signer)
addr = crypto.PubkeyToAddress(key.PublicKey)
expectedSuccessionNumber := 2
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
_, err := chain.InsertChain([]*types.Block{block})
assert.Equal(t,
*err.(*bor.BlockTooSoonError),
bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
header := block.Header()
header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor))
sign(t, header, signerKey)
block = types.NewBlockWithHeader(header)
_, err = chain.InsertChain([]*types.Block{block})
assert.Equal(t,
*err.(*bor.WrongDifficultyError),
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
sign(t, header, signerKey)
block = types.NewBlockWithHeader(header)
_, err = chain.InsertChain([]*types.Block{block})
assert.Nil(t, err)
}
func TestSignerNotFound(t *testing.T) {
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
h, _ := getMockedHeimdallClient(t)
_bor.SetHeimdallClient(h)
db := init.ethereum.ChainDb()
block := init.genesis.ToBlock(db)
// random signer account that is not a part of the validator set
signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
signerKey, _ := hex.DecodeString(signer)
key, _ = crypto.HexToECDSA(signer)
addr = crypto.PubkeyToAddress(key.PublicKey)
block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
_, err := chain.InsertChain([]*types.Block{block})
assert.Equal(t,
*err.(*bor.UnauthorizedSignerError),
bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
}
func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) {
res, heimdallSpan := loadSpanFromFile(t)
h := &mocks.IHeimdallClient{}
h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil)
h.On(
"FetchStateSyncEvents",
mock.AnythingOfType("uint64"),
mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil)
return h, heimdallSpan
}
func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime {
events := make([]*bor.EventRecordWithTime, count)
event := *sample
event.ID = 1
events[0] = &bor.EventRecordWithTime{}
*events[0] = event
for i := 1; i < count; i++ {
event.ID = uint64(i)
event.Time = event.Time.Add(1 * time.Second)
events[i] = &bor.EventRecordWithTime{}
*events[i] = event
}
return events
}
func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime {
event := *sample
event.ID = id
event.Time = time.Unix(timeStamp, 0)
return &event
}
func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
res := stateSyncEventsPayload(t)
var _eventRecords []*bor.EventRecordWithTime
if err := json.Unmarshal(res.Result, &_eventRecords); err != nil {
t.Fatalf("%s", err)
}
_eventRecords[0].Time = time.Unix(1, 0)
return _eventRecords[0]
}

172
tests/bor/helper.go Normal file
View file

@ -0,0 +1,172 @@
package bor
import (
"encoding/hex"
"encoding/json"
"io/ioutil"
"math/big"
"sort"
"testing"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/bor"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
var (
// The genesis for tests was generated with following parameters
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
// Only this account is a validator for the 0th span
privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
key, _ = crypto.HexToECDSA(privKey)
addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
// This account is one the validators for 1st span (0-indexed)
privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
key2, _ = crypto.HexToECDSA(privKey2)
addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
validatorHeaderBytesLength = common.AddressLength + 20 // address + power
sprintSize uint64 = 4
spanSize uint64 = 8
)
type initializeData struct {
genesis *core.Genesis
ethereum *eth.Ethereum
}
func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
genesisData, err := ioutil.ReadFile("./testdata/genesis.json")
if err != nil {
t.Fatalf("%s", err)
}
gen := &core.Genesis{}
if err := json.Unmarshal(genesisData, gen); err != nil {
t.Fatalf("%s", err)
}
ethConf := &eth.Config{
Genesis: gen,
}
ethConf.Genesis.MustCommit(db)
ethereum := utils.CreateBorEthereum(ethConf)
if err != nil {
t.Fatalf("failed to register Ethereum protocol: %v", err)
}
ethConf.Genesis.MustCommit(ethereum.ChainDb())
return &initializeData{
genesis: gen,
ethereum: ethereum,
}
}
func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
t.Fatalf("%s", err)
}
}
func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block {
header := block.Header()
header.Number.Add(header.Number, big.NewInt(1))
number := header.Number.Uint64()
if signer == nil {
signer = getSignerKey(header.Number.Uint64())
}
header.ParentHash = block.Hash()
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
header.Extra = make([]byte, 32+65) // vanity + extraSeal
currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)}
isSpanEnd := (number+1)%spanSize == 0
isSpanStart := number%spanSize == 0
isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
if isSpanEnd {
_, heimdallSpan := loadSpanFromFile(t)
// this is to stash the validator bytes in the header
currentValidators = heimdallSpan.ValidatorSet.Validators
} else if isSpanStart {
header.Difficulty = new(big.Int).SetInt64(3)
}
if isSprintEnd {
sort.Sort(bor.ValidatorsByAddress(currentValidators))
validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength)
header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal
for i, val := range currentValidators {
copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes())
}
copy(header.Extra[32:], validatorBytes)
}
state, err := chain.State()
if err != nil {
t.Fatalf("%s", err)
}
_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
if err != nil {
t.Fatalf("%s", err)
}
sign(t, header, signer)
return types.NewBlockWithHeader(header)
}
func sign(t *testing.T, header *types.Header, signer []byte) {
sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), signer)
if err != nil {
t.Fatalf("%s", err)
}
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
}
func stateSyncEventsPayload(t *testing.T) *bor.ResponseWithHeight {
stateData, err := ioutil.ReadFile("./testdata/states.json")
if err != nil {
t.Fatalf("%s", err)
}
res := &bor.ResponseWithHeight{}
if err := json.Unmarshal(stateData, res); err != nil {
t.Fatalf("%s", err)
}
return res
}
func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) {
spanData, err := ioutil.ReadFile("./testdata/span.json")
if err != nil {
t.Fatalf("%s", err)
}
res := &bor.ResponseWithHeight{}
if err := json.Unmarshal(spanData, res); err != nil {
t.Fatalf("%s", err)
}
heimdallSpan := &bor.HeimdallSpan{}
if err := json.Unmarshal(res.Result, heimdallSpan); err != nil {
t.Fatalf("%s", err)
}
return res, heimdallSpan
}
func getSignerKey(number uint64) []byte {
signerKey := privKey
isSpanStart := number%spanSize == 0
if isSpanStart {
// validator set in the new span has changed
signerKey = privKey2
}
_key, _ := hex.DecodeString(signerKey)
return _key
}

View file

@ -0,0 +1,82 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
package mocks
import (
bor "github.com/ethereum/go-ethereum/consensus/bor"
mock "github.com/stretchr/testify/mock"
)
// IHeimdallClient is an autogenerated mock type for the IHeimdallClient type
type IHeimdallClient struct {
mock.Mock
}
// Fetch provides a mock function with given fields: path, query
func (_m *IHeimdallClient) Fetch(path string, query string) (*bor.ResponseWithHeight, error) {
ret := _m.Called(path, query)
var r0 *bor.ResponseWithHeight
if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
r0 = rf(path, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bor.ResponseWithHeight)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(path, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FetchStateSyncEvents provides a mock function with given fields: fromID, to
func (_m *IHeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*bor.EventRecordWithTime, error) {
ret := _m.Called(fromID, to)
var r0 []*bor.EventRecordWithTime
if rf, ok := ret.Get(0).(func(uint64, int64) []*bor.EventRecordWithTime); ok {
r0 = rf(fromID, to)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*bor.EventRecordWithTime)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(uint64, int64) error); ok {
r1 = rf(fromID, to)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FetchWithRetry provides a mock function with given fields: path, query
func (_m *IHeimdallClient) FetchWithRetry(path string, query string) (*bor.ResponseWithHeight, error) {
ret := _m.Called(path, query)
var r0 *bor.ResponseWithHeight
if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
r0 = rf(path, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bor.ResponseWithHeight)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(path, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}

47
tests/bor/testdata/genesis.json vendored Normal file

File diff suppressed because one or more lines are too long

67
tests/bor/testdata/span.json vendored Normal file
View file

@ -0,0 +1,67 @@
{
"height": "42841",
"result": {
"span_id": 1,
"start_block": 256,
"end_block": 6655,
"validator_set": {
"validators": [{
"ID": 5,
"startEpoch": 0,
"endEpoch": 0,
"power": 30,
"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
"signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791",
"last_updated": 0,
"accum": 10000
}, {
"ID": 1,
"startEpoch": 0,
"endEpoch": 0,
"power": 20,
"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
"signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a",
"last_updated": 0,
"accum": 10000
}, {
"ID": 2,
"startEpoch": 0,
"endEpoch": 0,
"power": 10,
"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
"last_updated": 0,
"accum": 5000
}]
},
"selected_producers": [{
"ID": 5,
"startEpoch": 0,
"endEpoch": 0,
"power": 30,
"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
"signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791",
"last_updated": 0,
"accum": 10000
}, {
"ID": 1,
"startEpoch": 0,
"endEpoch": 0,
"power": 20,
"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
"signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a",
"last_updated": 0,
"accum": 10000
}, {
"ID": 2,
"startEpoch": 0,
"endEpoch": 0,
"power": 10,
"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
"last_updated": 0,
"accum": 5000
}],
"bor_chain_id": "15001"
}
}

23
tests/bor/testdata/states.json vendored Normal file
View file

@ -0,0 +1,23 @@
{
"height": "0",
"result": [
{
"id": 1,
"contract": "0xb55969a6d60413a63291a1de572269875df541e3",
"data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014",
"tx_hash": "0x7b113e09d98b6d4be1dedfbc0746e34876de767f2cb8b58ff00160a160811dd6",
"log_index": 0,
"bor_chain_id": "15001",
"record_time": "2020-05-15T13:36:38.580995Z"
},
{
"id": 2,
"contract": "0xb55969a6d60413a63291a1de572269875df541e3",
"data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000015",
"tx_hash": "0xb72358aff8e4d61f4de97a37a40ddda986c081e0de8036e0a78c4b61b067cba9",
"log_index": 0,
"bor_chain_id": "15001",
"record_time": "2020-05-15T13:42:37.319058Z"
}
]
}