Commit 82cad4ce authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

wait for eth backend to be synced (#1154)

parent 0ead1204
......@@ -185,6 +185,19 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
chequeSigner := chequebook.NewChequeSigner(signer, chainID.Int64())
maxDelay := 1 * time.Minute
synced, err := transaction.IsSynced(p2pCtx, swapBackend, maxDelay)
if err != nil {
return nil, err
}
if !synced {
logger.Infof("waiting for ethereum backend to be synced.")
err = transaction.WaitSynced(p2pCtx, swapBackend, maxDelay)
if err != nil {
return nil, fmt.Errorf("could not wait for ethereum backend to sync: %w", err)
}
}
// initialize chequebook logic
chequebookService, err = chequebook.Init(p2pCtx,
chequebookFactory,
......
......@@ -6,6 +6,8 @@ package transaction
import (
"context"
"math/big"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -17,4 +19,35 @@ type Backend interface {
bind.ContractBackend
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error)
BlockNumber(ctx context.Context) (uint64, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
}
func IsSynced(ctx context.Context, backend Backend, maxDelay time.Duration) (bool, error) {
number, err := backend.BlockNumber(ctx)
if err != nil {
return false, err
}
header, err := backend.HeaderByNumber(ctx, big.NewInt(int64(number)))
if err != nil {
return false, err
}
blockTime := time.Unix(int64(header.Time), 0)
return blockTime.After(time.Now().UTC().Add(-maxDelay)), nil
}
func WaitSynced(ctx context.Context, backend Backend, maxDelay time.Duration) error {
for {
synced, err := IsSynced(ctx, backend, maxDelay)
if err != nil {
return err
}
if synced {
return nil
}
}
}
package transaction_test
import (
"context"
"errors"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction"
"github.com/ethersphere/bee/pkg/settlement/swap/transaction/backendmock"
)
func TestIsSynced(t *testing.T) {
maxDelay := 10 * time.Second
now := time.Now().UTC()
ctx := context.Background()
blockNumber := uint64(100)
t.Run("synced", func(t *testing.T) {
synced, err := transaction.IsSynced(
ctx,
backendmock.New(
backendmock.WithBlockNumberFunc(func(c context.Context) (uint64, error) {
return blockNumber, nil
}),
backendmock.WithHeaderbyNumberFunc(func(ctx context.Context, number *big.Int) (*types.Header, error) {
if number.Uint64() != blockNumber {
return nil, errors.New("called with wrong block number")
}
return &types.Header{
Time: uint64(now.Unix()),
}, nil
}),
),
maxDelay,
)
if err != nil {
t.Fatal(err)
}
if !synced {
t.Fatal("expected synced")
}
})
t.Run("not synced", func(t *testing.T) {
synced, err := transaction.IsSynced(
ctx,
backendmock.New(
backendmock.WithBlockNumberFunc(func(c context.Context) (uint64, error) {
return blockNumber, nil
}),
backendmock.WithHeaderbyNumberFunc(func(ctx context.Context, number *big.Int) (*types.Header, error) {
if number.Uint64() != blockNumber {
return nil, errors.New("called with wrong block number")
}
return &types.Header{
Time: uint64(now.Add(-maxDelay).Unix()),
}, nil
}),
),
maxDelay,
)
if err != nil {
t.Fatal(err)
}
if synced {
t.Fatal("expected not synced")
}
})
t.Run("error", func(t *testing.T) {
expectedErr := errors.New("err")
_, err := transaction.IsSynced(
ctx,
backendmock.New(
backendmock.WithBlockNumberFunc(func(c context.Context) (uint64, error) {
return blockNumber, nil
}),
backendmock.WithHeaderbyNumberFunc(func(ctx context.Context, number *big.Int) (*types.Header, error) {
if number.Uint64() != blockNumber {
return nil, errors.New("called with wrong block number")
}
return nil, expectedErr
}),
),
maxDelay,
)
if !errors.Is(err, expectedErr) {
t.Fatalf("expected error. wanted %v, got %v", expectedErr, err)
}
})
}
......@@ -23,6 +23,8 @@ type backendMock struct {
transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
pendingNonceAt func(ctx context.Context, account common.Address) (uint64, error)
transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error)
blockNumber func(ctx context.Context) (uint64, error)
headerByNumber func(ctx context.Context, number *big.Int) (*types.Header, error)
}
func (m *backendMock) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
......@@ -90,6 +92,20 @@ func (m *backendMock) TransactionByHash(ctx context.Context, hash common.Hash) (
return nil, false, errors.New("not implemented")
}
func (m *backendMock) BlockNumber(ctx context.Context) (uint64, error) {
if m.blockNumber != nil {
return m.blockNumber(ctx)
}
return 0, errors.New("not implemented")
}
func (m *backendMock) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
if m.headerByNumber != nil {
return m.headerByNumber(ctx, number)
}
return nil, errors.New("not implemented")
}
func New(opts ...Option) transaction.Backend {
mock := new(backendMock)
for _, o := range opts {
......@@ -148,3 +164,15 @@ func WithSendTransactionFunc(f func(ctx context.Context, tx *types.Transaction)
s.sendTransaction = f
})
}
func WithBlockNumberFunc(f func(context.Context) (uint64, error)) Option {
return optionFunc(func(s *backendMock) {
s.blockNumber = f
})
}
func WithHeaderbyNumberFunc(f func(ctx context.Context, number *big.Int) (*types.Header, error)) Option {
return optionFunc(func(s *backendMock) {
s.headerByNumber = f
})
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment