Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pkg/**/gen/*/*.go
tools/**/gen/*/*.go
!tools/generators/promise/gen/*.go
!tools/generators/promise/gen/async/*.go
10 changes: 5 additions & 5 deletions pkg/chain/ethereum/block_counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,12 @@ func (bc *BlockCounter) subscribeBlocks(
}
}()

lastBlock, err := chainReader.BlockByNumber(ctx, nil)
lastHeader, err := chainReader.HeaderByNumber(ctx, nil)
if err != nil {
return err
}

bc.subscriptionChannel <- block{lastBlock.Number.String()}
bc.subscriptionChannel <- block{lastHeader.Number.String()}

return nil
}
Expand All @@ -215,17 +215,17 @@ func (bc *BlockCounter) subscribeBlocks(
func CreateBlockCounter(chainReader ChainReader) (*BlockCounter, error) {
ctx := context.Background()

startupBlock, err := chainReader.BlockByNumber(ctx, nil)
startupHeader, err := chainReader.HeaderByNumber(ctx, nil)
if err != nil {
return nil,
fmt.Errorf(
"failed to get initial block from the chain: [%v]",
"failed to get initial block header from the chain: [%v]",
err,
)
}

blockCounter := &BlockCounter{
latestBlockHeight: startupBlock.Number.Uint64(),
latestBlockHeight: startupHeader.Number.Uint64(),
waiters: make(map[uint64][]chan uint64),
subscriptionChannel: make(chan block),
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/chain/ethereum/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ type Subscription interface {

// ChainReader provides access to the blockchain.
type ChainReader interface {
// BlockByNumber gets the block by its number. The block number argument
// can be nil to select the latest block.
BlockByNumber(ctx context.Context, number *big.Int) (*Block, error)
// HeaderByNumber gets the block header by its number. The block header
// number argument can be nil to select the latest block header.
HeaderByNumber(ctx context.Context, number *big.Int) (*Header, error)

// SubscribeNewHead subscribes to notifications about changes of the
// head block of the canonical chain.
Expand Down
12 changes: 5 additions & 7 deletions pkg/chain/ethereum/ethutil/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@ type ethereumAdapter struct {
delegate EthereumClient
}

func (ea *ethereumAdapter) BlockByNumber(
func (ea *ethereumAdapter) HeaderByNumber(
ctx context.Context,
number *big.Int,
) (*chainEthereum.Block, error) {
block, err := ea.delegate.BlockByNumber(ctx, number)
) (*chainEthereum.Header, error) {
header, err := ea.delegate.HeaderByNumber(ctx, number)
if err != nil {
return nil, err
}

return &chainEthereum.Block{
Header: &chainEthereum.Header{
Number: block.Number(),
},
return &chainEthereum.Header{
Number: header.Number,
}, nil
}

Expand Down
40 changes: 19 additions & 21 deletions pkg/chain/ethereum/ethutil/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
chainEthereum "github.com/keep-network/keep-common/pkg/chain/ethereum"
)

func TestEthereumAdapter_BlockByNumber(t *testing.T) {
func TestEthereumAdapter_HeaderByNumber(t *testing.T) {
client := &mockAdaptedEthereumClient{
blocks: []*big.Int{
big.NewInt(0),
Expand All @@ -31,35 +31,35 @@ func TestEthereumAdapter_BlockByNumber(t *testing.T) {

adapter := &ethereumAdapter{client}

blockOne, err := adapter.BlockByNumber(context.Background(), big.NewInt(1))
headerOne, err := adapter.HeaderByNumber(context.Background(), big.NewInt(1))
if err != nil {
t.Fatal(err)
}

lastBlock, err := adapter.BlockByNumber(context.Background(), nil)
lastHeader, err := adapter.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatal(err)
}

expectedBlockOneNumber := big.NewInt(1)
if expectedBlockOneNumber.Cmp(blockOne.Number) != 0 {
expectedHeaderOneNumber := big.NewInt(1)
if expectedHeaderOneNumber.Cmp(headerOne.Number) != 0 {
t.Errorf(
"unexpected block number\n"+
"unexpected header number\n"+
"expected: [%v]\n"+
"actual: [%v]",
expectedBlockOneNumber,
blockOne.Number,
expectedHeaderOneNumber,
headerOne.Number,
)
}

expectedLastBlockNumber := big.NewInt(2)
if expectedLastBlockNumber.Cmp(lastBlock.Number) != 0 {
expectedLastHeaderNumber := big.NewInt(2)
if expectedLastHeaderNumber.Cmp(lastHeader.Number) != 0 {
t.Errorf(
"unexpected last block number\n"+
"unexpected last header number\n"+
"expected: [%v]\n"+
"actual: [%v]",
expectedLastBlockNumber,
lastBlock.Number,
expectedLastHeaderNumber,
lastHeader.Number,
)
}
}
Expand Down Expand Up @@ -166,22 +166,20 @@ type mockAdaptedEthereumClient struct {
nonces map[common.Address]uint64
}

func (maec *mockAdaptedEthereumClient) BlockByNumber(
func (maec *mockAdaptedEthereumClient) HeaderByNumber(
ctx context.Context,
number *big.Int,
) (*types.Block, error) {
) (*types.Header, error) {
index := len(maec.blocks) - 1

if number != nil {
index = int(number.Int64())
}

return types.NewBlockWithHeader(
&types.Header{
Number: maec.blocks[index],
BaseFee: maec.blocksBaseFee[index],
},
), nil
return &types.Header{
Number: maec.blocks[index],
BaseFee: maec.blocksBaseFee[index],
}, nil
}

func (maec *mockAdaptedEthereumClient) SubscribeNewHead(
Expand Down
12 changes: 6 additions & 6 deletions pkg/chain/ethereum/ethutil/mining_waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ var (
// increase the transaction's chance for being picked up by miners.
//
// Specific action depends on transaction type:
// - legacy pre EIP-1559 transaction: bumps up the gas price by 20%
// - dynamic fee post EIP-1559 transaction: bumps up the gas tip cap by 20%
// and adjusts the gas fee cap accordingly
// - legacy pre EIP-1559 transaction: bumps up the gas price by 20%
// - dynamic fee post EIP-1559 transaction: bumps up the gas tip cap by 20%
// and adjusts the gas fee cap accordingly
type MiningWaiter struct {
client EthereumClient
checkInterval time.Duration
Expand Down Expand Up @@ -391,15 +391,15 @@ func (mw *MiningWaiter) forceMiningDynamicFeeTx(
}

func (mw *MiningWaiter) latestBaseFee() (*big.Int, error) {
latestBlock, err := mw.client.BlockByNumber(
latestHeader, err := mw.client.HeaderByNumber(
context.Background(),
nil,
)
if err != nil {
return nil, fmt.Errorf("could not get the latest block: [%v]", err)
return nil, fmt.Errorf("could not get the latest block header: [%v]", err)
}

baseFee := latestBlock.BaseFee()
baseFee := latestHeader.BaseFee
if baseFee == nil {
return nil, fmt.Errorf("not an EIP-1559 block")
}
Expand Down
152 changes: 152 additions & 0 deletions tools/generators/promise/gen/async/big_int_promise.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Package async contains promise implementations generated for specific types.
// This is auto generated code.
package async

import (
"fmt"
"math/big"
"sync"
)

// BigIntPromise represents an eventual completion of an ansynchronous
// operation and its resulting value. Promise can be either fulfilled or
// failed and it can happen only one time. All Promise operations are
// thread-safe. To create a promise use: `&BigIntPromise{}`
type BigIntPromise struct {
mutex sync.Mutex
successFn func(*big.Int)
failureFn func(error)
completeFn func(*big.Int, error)

isComplete bool
value *big.Int
err error
}

// OnSuccess registers a function to be called when the Promise
// has been fulfilled. In case of a failed Promise, function is not
// called at all. OnSuccess is a non-blocking operation. Only one on success
// function can be registered for a Promise. If the Promise has been already
// fulfilled, the function is called immediatelly.
func (p *BigIntPromise) OnSuccess(onSuccess func(*big.Int)) *BigIntPromise {
p.mutex.Lock()
defer p.mutex.Unlock()

p.successFn = onSuccess

if p.isComplete && p.err == nil {
p.callSuccessFn()
}

return p
}

// OnFailure registers a function to be called when the Promise
// execution failed. In case of a fulfilled Promise, function is not
// called at all. OnFailure is a non-blocking operation. Only one on failure
// function can be registered for a Promise. If the Promise has already failed,
// the function is called immediatelly.
func (p *BigIntPromise) OnFailure(onFailure func(error)) *BigIntPromise {
p.mutex.Lock()
defer p.mutex.Unlock()

p.failureFn = onFailure

if p.isComplete && p.err != nil {
p.callFailureFn()
}

return p
}

// OnComplete registers a function to be called when the Promise
// execution completed no matter if it succeded or failed.
// In case of a successful execution, error passed to the callback
// function is nil. In case of a failed execution, there is no
// value evaluated so the value parameter is nil. OnComplete is
// a non-blocking operation. Only one on complete function can be
// registered for a Promise. If the Promise has already completed,
// the function is called immediatelly.
func (p *BigIntPromise) OnComplete(onComplete func(*big.Int, error)) *BigIntPromise {
p.mutex.Lock()
defer p.mutex.Unlock()

p.completeFn = onComplete

if p.isComplete {
p.callCompleteFn()
}

return p
}

// Fulfill can happen only once for a Promise and it results in calling
// the OnSuccess callback, if registered. If Promise has been already
// completed by either fulfilling or failing, this function reports
// an error.
func (p *BigIntPromise) Fulfill(value *big.Int) error {
p.mutex.Lock()
defer p.mutex.Unlock()

if p.isComplete {
return fmt.Errorf("promise already completed")
}

p.isComplete = true
p.value = value

p.callSuccessFn()
p.callCompleteFn()

return nil
}

// Fail can happen only once for a Promise and it results in calling
// the OnFailure callback, if registered. If Promise has been already
// completed by either fulfilling or failing, this function reports
// an error. Also, this function reports an error if `err` parameter
// is `nil`.
func (p *BigIntPromise) Fail(err error) error {
p.mutex.Lock()
defer p.mutex.Unlock()

if err == nil {
return fmt.Errorf("error cannot be nil")
}

if p.isComplete {
return fmt.Errorf("promise already completed")
}

p.isComplete = true
p.err = err

p.callFailureFn()
p.callCompleteFn()

return nil
}

func (p *BigIntPromise) callCompleteFn() {
if p.completeFn != nil {
go func() {
p.completeFn(p.value, p.err)
}()
}
}

func (p *BigIntPromise) callSuccessFn() {
if p.successFn != nil {
go func() {
p.successFn(p.value)
}()
}
}

func (p *BigIntPromise) callFailureFn() {
if p.failureFn != nil {
go func() {
p.failureFn(p.err)
}()
}
}
Loading