2022-06-13 13:43:09 +00:00
package builder
import (
"sync"
"sync/atomic"
2022-10-14 23:12:38 +00:00
"time"
2022-06-13 13:43:09 +00:00
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/log/v3"
)
type BlockBuilderFunc func ( param * core . BlockBuilderParameters , interrupt * int32 ) ( * types . Block , error )
// BlockBuilder wraps a goroutine that builds Proof-of-Stake payloads (PoS "mining")
type BlockBuilder struct {
emptyHeader * types . Header
interrupt int32
syncCond * sync . Cond
block * types . Block
err error
}
func NewBlockBuilder ( build BlockBuilderFunc , param * core . BlockBuilderParameters , emptyHeader * types . Header ) * BlockBuilder {
b := new ( BlockBuilder )
b . emptyHeader = emptyHeader
b . syncCond = sync . NewCond ( new ( sync . Mutex ) )
go func ( ) {
2022-10-14 23:12:38 +00:00
log . Debug ( "Building block..." )
t := time . Now ( )
2022-06-13 13:43:09 +00:00
block , err := build ( param , & b . interrupt )
2022-10-14 23:12:38 +00:00
log . Debug ( "Built block" , "hash" , block . Hash ( ) , "height" , block . NumberU64 ( ) , "txs" , len ( block . Transactions ( ) ) , "gas used %" , 100 * float64 ( block . GasUsed ( ) ) / float64 ( block . GasLimit ( ) ) , "time" , time . Since ( t ) )
2022-06-13 13:43:09 +00:00
b . syncCond . L . Lock ( )
defer b . syncCond . L . Unlock ( )
b . block = block
b . err = err
b . syncCond . Broadcast ( )
} ( )
return b
}
func ( b * BlockBuilder ) Stop ( ) * types . Block {
atomic . StoreInt32 ( & b . interrupt , 1 )
b . syncCond . L . Lock ( )
defer b . syncCond . L . Unlock ( )
for b . block == nil && b . err == nil {
b . syncCond . Wait ( )
}
if b . err != nil {
log . Error ( "BlockBuilder" , "err" , b . err )
return types . NewBlock ( b . emptyHeader , nil , nil , nil )
}
return b . block
}
2022-08-15 08:19:45 +00:00
func ( b * BlockBuilder ) Block ( ) * types . Block {
b . syncCond . L . Lock ( )
defer b . syncCond . L . Unlock ( )
return b . block
}