From 5908a8c3727d18eef740e7f78ec008abdd157ad1 Mon Sep 17 00:00:00 2001 From: PJ Date: Wed, 17 Apr 2024 12:36:49 +0200 Subject: [PATCH 1/3] testutil: fix miner fees race in MineBlock --- testutil/network.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/testutil/network.go b/testutil/network.go index d595ba7..2db8e52 100644 --- a/testutil/network.go +++ b/testutil/network.go @@ -28,18 +28,19 @@ func Network() (*consensus.Network, types.Block) { // MineBlock mines a block with the given transactions, transaction fees are // added to the miner payout. func MineBlock(cm *chain.Manager, minerAddress types.Address) types.Block { - var minerFees types.Currency - for _, txn := range cm.PoolTransactions() { - minerFees = minerFees.Add(txn.TotalFees()) - } - state := cm.TipState() b := types.Block{ ParentID: state.Index.ID, Timestamp: types.CurrentTimestamp(), Transactions: cm.PoolTransactions(), - MinerPayouts: []types.SiacoinOutput{{Address: minerAddress, Value: state.BlockReward().Add(minerFees)}}, + MinerPayouts: []types.SiacoinOutput{{Address: minerAddress, Value: state.BlockReward()}}, } + + // add txn fees to miner payout + for _, txn := range b.Transactions { + b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.TotalFees()) + } + if !coreutils.FindBlockNonce(state, &b, 5*time.Second) { panic("failed to find nonce") } From e6092bdaf317a0f3a001f34ec03c5379a3a84a1b Mon Sep 17 00:00:00 2001 From: PJ Date: Wed, 17 Apr 2024 19:54:13 +0200 Subject: [PATCH 2/3] testutil: remove MineBlock in favour of impl in coreutils package --- testutil/network.go | 25 ------------------------- wallet/wallet_test.go | 4 +++- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/testutil/network.go b/testutil/network.go index 2db8e52..e57e453 100644 --- a/testutil/network.go +++ b/testutil/network.go @@ -1,11 +1,8 @@ package testutil import ( - "time" - "go.sia.tech/core/consensus" "go.sia.tech/core/types" - "go.sia.tech/coreutils" "go.sia.tech/coreutils/chain" ) @@ -24,25 +21,3 @@ func Network() (*consensus.Network, types.Block) { n.HardforkV2.RequireHeight = 250 return n, genesisBlock } - -// MineBlock mines a block with the given transactions, transaction fees are -// added to the miner payout. -func MineBlock(cm *chain.Manager, minerAddress types.Address) types.Block { - state := cm.TipState() - b := types.Block{ - ParentID: state.Index.ID, - Timestamp: types.CurrentTimestamp(), - Transactions: cm.PoolTransactions(), - MinerPayouts: []types.SiacoinOutput{{Address: minerAddress, Value: state.BlockReward()}}, - } - - // add txn fees to miner payout - for _, txn := range b.Transactions { - b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.TotalFees()) - } - - if !coreutils.FindBlockNonce(state, &b, 5*time.Second) { - panic("failed to find nonce") - } - return b -} diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index 8828786..7742204 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -37,7 +37,9 @@ func syncDB(cm *chain.Manager, store wallet.SingleAddressStore) error { func mineAndSync(cm *chain.Manager, ws wallet.SingleAddressStore, address types.Address, n uint64) error { // mine n blocks for i := uint64(0); i < n; i++ { - if err := cm.AddBlocks([]types.Block{testutil.MineBlock(cm, address)}); err != nil { + if block, found := coreutils.MineBlock(cm, address, 5*time.Second); !found { + panic("failed to mine block") + } else if err := cm.AddBlocks([]types.Block{block}); err != nil { return fmt.Errorf("failed to add blocks: %w", err) } } From 018cccd2ed9dc90fd08328419058ca8fc65d64e9 Mon Sep 17 00:00:00 2001 From: PJ Date: Wed, 17 Apr 2024 19:57:59 +0200 Subject: [PATCH 3/3] miner: avoid race involving tip change when fetching v1 and v2 pool txns --- miner.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/miner.go b/miner.go index fef434e..b08680a 100644 --- a/miner.go +++ b/miner.go @@ -38,7 +38,14 @@ func FindBlockNonce(cs consensus.State, b *types.Block, timeout time.Duration) b // MineBlock constructs a block from the provided address and the transactions // in the txpool, and attempts to find a nonce for it that meets the PoW target. func MineBlock(cm *chain.Manager, addr types.Address, timeout time.Duration) (types.Block, bool) { +retry: cs := cm.TipState() + txns := cm.PoolTransactions() + v2Txns := cm.V2PoolTransactions() + if cs.Index != cm.Tip() { + goto retry + } + b := types.Block{ ParentID: cs.Index.ID, Timestamp: types.CurrentTimestamp(), @@ -48,14 +55,14 @@ func MineBlock(cm *chain.Manager, addr types.Address, timeout time.Duration) (ty }}, } var weight uint64 - for _, txn := range cm.PoolTransactions() { + for _, txn := range txns { if weight += cs.TransactionWeight(txn); weight > cs.MaxBlockWeight() { break } b.Transactions = append(b.Transactions, txn) b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(txn.TotalFees()) } - for _, txn := range cm.V2PoolTransactions() { + for _, txn := range v2Txns { if weight += cs.V2TransactionWeight(txn); weight > cs.MaxBlockWeight() { break }