good morning!!!!

Skip to content
Snippets Groups Projects
Commit 9dd4e4b0 authored by atvanguard's avatar atvanguard
Browse files

Refactor HeimdallClient + commitSpan test :construction:

parent 57ccdb54
No related branches found
No related tags found
No related merge requests found
......@@ -30,6 +30,10 @@ type API struct {
bor *Bor
}
func NewBorApi(chain consensus.ChainReader, bor *Bor) API {
return API{chain: chain, bor: bor}
}
// GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
// Retrieve the requested block number (or current if none requested)
......
......@@ -10,7 +10,8 @@ import (
"io"
"math"
"math/big"
"net/http"
// "net/http"
"sort"
"strconv"
"strings"
......@@ -243,7 +244,7 @@ type Bor struct {
ethAPI *ethapi.PublicBlockChainAPI
validatorSetABI abi.ABI
stateReceiverABI abi.ABI
httpClient http.Client
HeimdallClient IHeimdallClient
// The fields below are for testing only
fakeDiff bool // Skip difficulty verifications
......@@ -268,6 +269,8 @@ func New(
signatures, _ := lru.NewARC(inmemorySignatures)
vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
heimdallClient, _ := NewHeimdallClient(chainConfig.Bor.Heimdall)
c := &Bor{
chainConfig: chainConfig,
config: borConfig,
......@@ -277,9 +280,7 @@ func New(
signatures: signatures,
validatorSetABI: vABI,
stateReceiverABI: sABI,
httpClient: http.Client{
Timeout: time.Duration(5 * time.Second),
},
HeimdallClient: heimdallClient,
}
return c
......@@ -662,20 +663,26 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
// rewards given.
func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
// commit span
if header.Number.Uint64()%c.config.Sprint == 0 {
headerNumber := header.Number.Uint64()
fmt.Println(header.Number, headerNumber % c.config.Sprint)
if headerNumber > 0 &&
headerNumber % c.config.Sprint == 0 {
cx := chainContext{Chain: chain, Bor: c}
fmt.Println("here 0.1")
// check and commit span
if err := c.checkAndCommitSpan(state, header, cx); err != nil {
fmt.Println("Error while committing span", err)
log.Error("Error while committing span", "error", err)
return
}
fmt.Println("here 11")
// commit statees
if err := c.CommitStates(state, header, cx); err != nil {
log.Error("Error while committing states", "error", err)
return
}
// if err := c.CommitStates(state, header, cx); err != nil {
// log.Error("Error while committing states", "error", err)
// fmt.Println("here 12", err)
// return
// }
fmt.Println("here 12")
}
// No block rewards in PoA, so the state remains as is and uncles are dropped
......@@ -986,33 +993,53 @@ func (c *Bor) checkAndCommitSpan(
header *types.Header,
chain core.ChainContext,
) error {
headerNumber := header.Number.Uint64()
pending := false
var span *Span = nil
var wg sync.WaitGroup
wg.Add(1)
errors := make(chan error)
// var wg sync.WaitGroup
// wg.Add(1)
go func() {
pending, _ = c.isSpanPending(header.Number.Uint64())
wg.Done()
var err error
pending, err = c.isSpanPending(headerNumber - 1)
errors <- err
// wg.Done()
}()
wg.Add(1)
// wg.Add(1)
go func() {
span, _ = c.GetCurrentSpan(header.Number.Uint64() - 1)
wg.Done()
var err error
span, err = c.GetCurrentSpan(headerNumber - 1)
errors <- err
// wg.Done()
}()
wg.Wait()
var err error
for i := 0; i < 2; i++ {
err = <- errors
if err != nil {
// fmt.Println(i, err)
return err
}
}
fmt.Println("here 1")
// commit span if there is new span pending or span is ending or end block is not set
if pending || c.needToCommitSpan(span, header) {
err := c.commitSpan(span, state, header, chain)
if pending || c.needToCommitSpan(span, headerNumber) {
fmt.Println("here 2", span)
err := c.fetchAndCommitSpan(span.ID + 1, state, header, chain)
// err := c.commitSpan(span, state, header, chain)
fmt.Println("here 10", err)
return err
}
return nil
}
func (c *Bor) needToCommitSpan(span *Span, header *types.Header) bool {
func (c *Bor) needToCommitSpan(span *Span, headerNumber uint64) bool {
fmt.Println("span", span)
// if span is nil
if span == nil {
return false
......@@ -1024,21 +1051,21 @@ func (c *Bor) needToCommitSpan(span *Span, header *types.Header) bool {
}
// if current block is first block of last sprint in current span
h := header.Number.Uint64()
if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == h {
if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == headerNumber {
return true
}
return false
}
func (c *Bor) commitSpan(
span *Span,
func (c *Bor) fetchAndCommitSpan(
newSpanID uint64,
state *state.StateDB,
header *types.Header,
chain core.ChainContext,
) error {
response, err := FetchFromHeimdallWithRetry(c.httpClient, c.chainConfig.Bor.Heimdall, "bor", "span", strconv.FormatUint(span.ID+1, 10))
response, err := c.HeimdallClient.FetchWithRetry("bor", "span", strconv.FormatUint(newSpanID, 10))
fmt.Println("here 3")
if err != nil {
return err
}
......@@ -1047,7 +1074,7 @@ func (c *Bor) commitSpan(
if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil {
return err
}
fmt.Println("here 4", heimdallSpan)
// check if chain id matches with heimdall span
if heimdallSpan.ChainID != c.chainConfig.ChainID.String() {
return fmt.Errorf(
......@@ -1056,7 +1083,7 @@ func (c *Bor) commitSpan(
c.chainConfig.ChainID,
)
}
fmt.Println("here 5")
// get validators bytes
var validators []MinimalVal
for _, val := range heimdallSpan.ValidatorSet.Validators {
......@@ -1066,7 +1093,7 @@ func (c *Bor) commitSpan(
if err != nil {
return err
}
fmt.Println("here 6")
// get producers bytes
var producers []MinimalVal
for _, val := range heimdallSpan.SelectedProducers {
......@@ -1086,7 +1113,7 @@ func (c *Bor) commitSpan(
"validatorBytes", hex.EncodeToString(validatorBytes),
"producerBytes", hex.EncodeToString(producerBytes),
)
fmt.Println("here 7")
// get packed data
data, err := c.validatorSetABI.Pack(method,
big.NewInt(0).SetUint64(heimdallSpan.ID),
......@@ -1099,10 +1126,10 @@ func (c *Bor) commitSpan(
log.Error("Unable to pack tx for commitSpan", "error", err)
return err
}
fmt.Println("here 8")
// get system message
msg := getSystemMessage(common.HexToAddress(c.config.ValidatorContract), data)
fmt.Println("here 9")
// apply message
return applyMessage(msg, state, header, c.chainConfig, chain)
}
......@@ -1166,7 +1193,7 @@ func (c *Bor) CommitStates(
// itereate through state ids
for _, stateID := range stateIds {
// fetch from heimdall
response, err := FetchFromHeimdallWithRetry(c.httpClient, c.chainConfig.Bor.Heimdall, "clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10))
response, err := c.HeimdallClient.FetchWithRetry("clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10))
if err != nil {
return err
}
......@@ -1218,6 +1245,10 @@ func (c *Bor) CommitStates(
return nil
}
func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
c.HeimdallClient = h
}
func (c *Bor) IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool {
header := chain.CurrentHeader()
snap, err := c.snapshot(chain, header.Number.Uint64(), header.Hash(), nil)
......@@ -1246,7 +1277,6 @@ func isProposeSpanAction(tx *types.Transaction, validatorContract string) bool {
func isProposeStateAction(tx *types.Transaction, stateReceiverContract string) bool {
// keccak256('proposeState(uint256)').slice(0, 4)
proposeStateSig, _ := hex.DecodeString("ede01f17")
fmt.Println(bytes.Compare(proposeStateSig, tx.Data()[:4]) == 0, tx.To().String(), stateReceiverContract)
return bytes.Compare(proposeStateSig, tx.Data()[:4]) == 0 &&
tx.To().String() == stateReceiverContract
}
......@@ -1265,6 +1295,10 @@ type chainContext struct {
Bor consensus.Engine
}
// func NewChainContext(chain consensus.ChainReader, bor consensus.Engine) (chainContext) {
// return {Chain: chain, Bor: bor}
// }
func (c chainContext) Engine() consensus.Engine {
return c.Bor
}
......@@ -1322,11 +1356,12 @@ func applyMessage(
msg.Gas(),
msg.Value(),
)
fmt.Println("here 9.1", err)
// Update the state with pending changes
if err != nil {
fmt.Println("here 9.2", err)
state.Finalise(true)
}
return nil
}
......
......@@ -19,69 +19,82 @@ type ResponseWithHeight struct {
Result json.RawMessage `json:"result"`
}
// internal fetch method
func internalFetch(client http.Client, u *url.URL) (*ResponseWithHeight, error) {
res, err := client.Get(u.String())
if err != nil {
return nil, err
type IHeimdallClient interface {
Fetch(paths ...string) (*ResponseWithHeight, error)
FetchWithRetry(paths ...string) (*ResponseWithHeight, error)
}
defer res.Body.Close()
// check status code
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error while fetching data from Heimdall")
type HeimdallClient struct {
u *url.URL
client http.Client
}
// get response
body, err := ioutil.ReadAll(res.Body)
func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
u, err := url.Parse(urlString)
if err != nil {
return nil, err
}
// unmarshall data from buffer
var response ResponseWithHeight
if err := json.Unmarshal(body, &response); err != nil {
return nil, err
h := &HeimdallClient{
u: u,
client: http.Client{
Timeout: time.Duration(5 * time.Second),
},
}
return &response, nil
return h, nil
}
// FetchFromHeimdallWithRetry returns data from heimdall with retry
func FetchFromHeimdallWithRetry(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) {
u, err := url.Parse(urlString)
if err != nil {
return nil, err
func (h *HeimdallClient) Fetch(paths ...string) (*ResponseWithHeight, error) {
for _, e := range paths {
if e != "" {
h.u.Path = path.Join(h.u.Path, e)
}
}
return h.internalFetch()
}
// FetchWithRetry returns data from heimdall with retry
func (h *HeimdallClient) FetchWithRetry(paths ...string) (*ResponseWithHeight, error) {
for _, e := range paths {
if e != "" {
u.Path = path.Join(u.Path, e)
h.u.Path = path.Join(h.u.Path, e)
}
}
for {
res, err := internalFetch(client, u)
res, err := h.internalFetch()
if err == nil && res != nil {
return res, nil
}
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", u.Path)
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", h.u.Path)
time.Sleep(5 * time.Second)
}
}
// FetchFromHeimdall returns data from heimdall
func FetchFromHeimdall(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) {
u, err := url.Parse(urlString)
// internal fetch method
func (h *HeimdallClient) internalFetch() (*ResponseWithHeight, error) {
res, err := h.client.Get(h.u.String())
if err != nil {
return nil, err
}
defer res.Body.Close()
for _, e := range paths {
if e != "" {
u.Path = path.Join(u.Path, e)
// check status code
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error while fetching data from Heimdall")
}
// get response
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
// unmarshall data from buffer
var response ResponseWithHeight
if err := json.Unmarshal(body, &response); err != nil {
return nil, err
}
return internalFetch(client, u)
return &response, nil
}
......@@ -3,34 +3,129 @@ package bor_test
import (
"encoding/hex"
"encoding/json"
"fmt"
// "fmt"
"io/ioutil"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
// "github.com/stretchr/testify/mock"
"github.com/maticnetwork/bor/common"
"github.com/maticnetwork/bor/consensus/bor"
"github.com/maticnetwork/bor/core"
"github.com/maticnetwork/bor/core/rawdb"
"github.com/maticnetwork/bor/core/state"
"github.com/maticnetwork/bor/core/types"
// "github.com/maticnetwork/bor/core/vm"
"github.com/maticnetwork/bor/crypto"
"github.com/maticnetwork/bor/eth"
"github.com/maticnetwork/bor/ethdb"
"github.com/maticnetwork/bor/mocks"
"github.com/maticnetwork/bor/node"
)
type initializeData struct {
genesis *core.Genesis
ethereum *eth.Ethereum
}
func TestCommitSpan(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
// key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
// addr = crypto.PubkeyToAddress(key.PublicKey)
)
init := buildEthereumInstance(t, db)
chain := init.ethereum.BlockChain()
engine := init.ethereum.Engine()
_bor := engine.(*bor.Bor)
spanData, err := ioutil.ReadFile("span.json")
if err != nil {
t.Fatalf("%s", err)
}
res := &bor.ResponseWithHeight{}
if err := json.Unmarshal(spanData, res); err != nil {
t.Fatalf("%s", err)
}
h := &mocks.IHeimdallClient{}
h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil)
_bor.SetHeimdallClient(h)
block := init.genesis.ToBlock(db)
statedb, _ := state.New(block.Root(), state.NewDatabase(db))
// _, _, _, err = chain.Processor().Process(block, statedb, vm.Config{})
// fmt.Println(err)
// _bor.Finalize(chain, block.Header(), statedb, nil, nil)
api := bor.NewBorApi(chain, _bor)
validators, _ := api.GetCurrentValidators()
fmt.Println(1, validators)
header := block.Header()
header.Number = big.NewInt(1)
header.ParentHash = block.Hash()
block = types.NewBlockWithHeader(header)
_bor.Finalize(chain, block.Header(), statedb, nil, nil)
// _, _, _, err = chain.Processor().Process(block, statedb, vm.Config{})
if err != nil {
t.Fatalf("%s", err)
}
// fmt.Println(header.Number)
// _bor.Finalize(chain, header, statedb, nil, nil)
// status, err := chain.writeBlockWithState(block, receipts, statedb)
// chain.chainmu.Lock()
k := big.NewInt(0)
k.Add(block.Difficulty(), chain.GetTdByHash(block.ParentHash()))
fmt.Println("k", k)
rawdb.WriteTd(db,
block.Hash(),
block.NumberU64(),
k,
)
rawdb.WriteBlock(db, block)
root, err := statedb.Commit(true /* false ??*/)
fmt.Println("root", root)
if err != nil {
t.Fatalf("%s", err)
}
if err := statedb.Reset(root); err != nil {
t.Fatalf("state reset after block %d failed: %v", block.NumberU64(), err)
}
// blockchain.chainmu.Unlock()
assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 1))
validators, _ = api.GetCurrentValidators()
fmt.Println(2, validators)
validators, _ = _bor.GetCurrentValidators(0, 255)
fmt.Println(3, validators)
validators, _ = _bor.GetCurrentValidators(0, 256)
fmt.Println(4, validators)
// validators, _ = _bor.GetCurrentValidators(1, 256)
// fmt.Println(4, validators)
// engine
}
func TestIsValidatorAction(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr = crypto.PubkeyToAddress(key.PublicKey)
)
ethereum := buildEthereumInstance(t, db)
init := buildEthereumInstance(t, db)
ethereum := init.ethereum
chain := ethereum.BlockChain()
engine := ethereum.Engine()
bor := engine.(*bor.Bor)
// proposeState
data, _ := hex.DecodeString("ede01f170000000000000000000000000000000000000000000000000000000000000000")
......@@ -40,7 +135,7 @@ func TestIsValidatorAction(t *testing.T) {
big.NewInt(0), 0, big.NewInt(0),
data,
)
assert.True(t, bor.IsValidatorAction(chain, addr, tx))
assert.True(t, engine.(*bor.Bor).IsValidatorAction(chain, addr, tx))
// proposeSpan
data, _ = hex.DecodeString("4b0e4d17")
......@@ -50,10 +145,10 @@ func TestIsValidatorAction(t *testing.T) {
big.NewInt(0), 0, big.NewInt(0),
data,
)
assert.True(t, bor.IsValidatorAction(chain, addr, tx))
assert.True(t, engine.(*bor.Bor).IsValidatorAction(chain, addr, tx))
}
func buildEthereumInstance(t *testing.T, db ethdb.Database) *eth.Ethereum {
func buildEthereumInstance(t *testing.T, db ethdb.Database) (*initializeData) {
genesisData, err := ioutil.ReadFile("genesis.json")
if err != nil {
t.Fatalf("%s", err)
......@@ -98,5 +193,9 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *eth.Ethereum {
var ethereum *eth.Ethereum
stack.Service(&ethereum)
return ethereum
return &initializeData{
genesis: gen,
ethereum: ethereum,
}
}
......@@ -11,7 +11,7 @@
"bor": {
"period": 1,
"producerDelay": 4,
"sprint": 64,
"sprint": 1,
"validatorContract": "0x0000000000000000000000000000000000001000",
"stateReceiverContract": "0x0000000000000000000000000000000000001001",
"heimdall": "http://localhost:1317"
......
{
"height": "42841",
"result": {
"span_id": 1,
"start_block": 256,
"end_block": 6655,
"validator_set": {
"validators": [{
"ID": 3,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1",
"signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220",
"last_updated": 0,
"accum": -40000
}, {
"ID": 4,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x04d9d09f2afc9da3cccc164e8112eb6911a63f5ede10169768f800df83cf99c73f944411e9d4fac3543b11c5f84a82e56b36cfcd34f1d065855c1e2b27af8b5247",
"signer": "0x461295d3d9249215e758e939a150ab180950720b",
"last_updated": 0,
"accum": 10000
}, {
"ID": 5,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
"signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0",
"last_updated": 0,
"accum": 10000
}, {
"ID": 1,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
"signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3",
"last_updated": 0,
"accum": 10000
}, {
"ID": 2,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
"last_updated": 0,
"accum": 10000
}],
"proposer": {
"ID": 3,
"startEpoch": 0,
"endEpoch": 0,
"power": 10000,
"pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1",
"signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220",
"last_updated": 0,
"accum": -40000
}
},
"selected_producers": [{
"ID": 5,
"startEpoch": 0,
"endEpoch": 0,
"power": 1,
"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
"signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0",
"last_updated": 0,
"accum": 10000
}, {
"ID": 1,
"startEpoch": 0,
"endEpoch": 0,
"power": 1,
"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
"signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3",
"last_updated": 0,
"accum": 10000
}, {
"ID": 2,
"startEpoch": 0,
"endEpoch": 0,
"power": 2,
"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
"last_updated": 0,
"accum": 10000
}],
"bor_chain_id": "15001"
}
}
// Code generated by mockery v1.0.0. DO NOT EDIT.
package mocks
import (
bor "github.com/maticnetwork/bor/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: paths
func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, error) {
_va := make([]interface{}, len(paths))
for _i := range paths {
_va[_i] = paths[_i]
}
var _ca []interface{}
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *bor.ResponseWithHeight
if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok {
r0 = rf(paths...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bor.ResponseWithHeight)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(...string) error); ok {
r1 = rf(paths...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// FetchWithRetry provides a mock function with given fields: paths
func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHeight, error) {
_va := make([]interface{}, len(paths))
for _i := range paths {
_va[_i] = paths[_i]
}
var _ca []interface{}
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *bor.ResponseWithHeight
if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok {
r0 = rf(paths...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*bor.ResponseWithHeight)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(...string) error); ok {
r1 = rf(paths...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment