Skip to content

Commit

Permalink
blockchain: Return uint256 from chain work method.
Browse files Browse the repository at this point in the history
This modifies the method that returns the total cumulative work for a
given block to return a more efficient uint256 instead of a big integer
and updates all consumers accordingly.
  • Loading branch information
davecgh committed Jun 9, 2022
1 parent 891fc80 commit b406a77
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 22 deletions.
7 changes: 3 additions & 4 deletions internal/blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"context"
"errors"
"fmt"
"math/big"
"sync"
"time"

Expand Down Expand Up @@ -463,13 +462,13 @@ func (b *BlockChain) HaveBlock(hash *chainhash.Hash) bool {

// ChainWork returns the total work up to and including the block of the
// provided block hash.
func (b *BlockChain) ChainWork(hash *chainhash.Hash) (*big.Int, error) {
func (b *BlockChain) ChainWork(hash *chainhash.Hash) (uint256.Uint256, error) {
node := b.index.LookupNode(hash)
if node == nil {
return nil, unknownBlockError(hash)
return uint256.Uint256{}, unknownBlockError(hash)
}

return node.workSum.ToBig(), nil
return node.workSum, nil
}

// TipGeneration returns the entire generation of blocks stemming from the
Expand Down
25 changes: 22 additions & 3 deletions internal/netsync/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/decred/dcrd/internal/blockchain"
"github.com/decred/dcrd/internal/mempool"
"github.com/decred/dcrd/internal/progresslog"
"github.com/decred/dcrd/math/uint256"
peerpkg "github.com/decred/dcrd/peer/v3"
"github.com/decred/dcrd/wire"
)
Expand Down Expand Up @@ -272,6 +273,14 @@ type SyncManager struct {
// creation time and treated as immutable after that.
cfg Config

// minKnownWork houses the minimum known work from the associated network
// params converted to a uint256 so the conversion only needs to be
// performed once when the sync manager is initialized. Ideally, the chain
// params should be updated to use the new type, but that will be a major
// version bump, so a one-time conversion is a good tradeoff in the mean
// time.
minKnownWork *uint256.Uint256

rejectedTxns *apbf.Filter
requestedTxns map[chainhash.Hash]struct{}
requestedBlocks map[chainhash.Hash]struct{}
Expand Down Expand Up @@ -1094,10 +1103,9 @@ func (m *SyncManager) handleHeadersMsg(hmsg *headersMsg) {
isChainCurrent := chain.IsCurrent()
receivedMaxHeaders := len(headers) == wire.MaxBlockHeadersPerMsg
if !isChainCurrent && !peer.Inbound() && !receivedMaxHeaders {
minKnownWork := m.cfg.ChainParams.MinKnownChainWork
if minKnownWork != nil {
if m.minKnownWork != nil {
workSum, err := chain.ChainWork(finalReceivedHash)
if err == nil && workSum.Cmp(minKnownWork) < 0 {
if err == nil && workSum.Lt(m.minKnownWork) {
log.Debugf("Best known chain for peer %s has too little "+
"cumulative work -- disconnecting", peer)
peer.Disconnect()
Expand Down Expand Up @@ -1771,12 +1779,23 @@ type Config struct {
// New returns a new network chain synchronization manager. Use Run to begin
// processing asynchronous events.
func New(config *Config) *SyncManager {
// Convert the minimum known work to a uint256 when it exists. Ideally, the
// chain params should be updated to use the new type, but that will be a
// major version bump, so a one-time conversion is a good tradeoff in the
// mean time.
var minKnownWork *uint256.Uint256
minKnownWorkBig := config.ChainParams.MinKnownChainWork
if minKnownWorkBig != nil {
minKnownWork = new(uint256.Uint256).SetBig(minKnownWorkBig)
}

return &SyncManager{
cfg: *config,
rejectedTxns: apbf.NewFilter(maxRejectedTxns, rejectedTxnsFPRate),
requestedTxns: make(map[chainhash.Hash]struct{}),
requestedBlocks: make(map[chainhash.Hash]struct{}),
peers: make(map[*peerpkg.Peer]*syncMgrPeer),
minKnownWork: minKnownWork,
hdrSyncState: makeHeaderSyncState(),
progressLogger: progresslog.New("Processed", log),
msgChan: make(chan interface{}, config.MaxPeers*3),
Expand Down
4 changes: 2 additions & 2 deletions internal/rpcserver/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package rpcserver

import (
"context"
"math/big"
"net"
"time"

Expand All @@ -19,6 +18,7 @@ import (
"github.com/decred/dcrd/internal/blockchain/indexers"
"github.com/decred/dcrd/internal/mempool"
"github.com/decred/dcrd/internal/mining"
"github.com/decred/dcrd/math/uint256"
"github.com/decred/dcrd/peer/v3"
"github.com/decred/dcrd/rpc/jsonrpc/types/v4"
"github.com/decred/dcrd/txscript/v4/stdaddr"
Expand Down Expand Up @@ -246,7 +246,7 @@ type Chain interface {

// ChainWork returns the total work up to and including the block of the
// provided block hash.
ChainWork(hash *chainhash.Hash) (*big.Int, error)
ChainWork(hash *chainhash.Hash) (uint256.Uint256, error)

// CheckLiveTicket returns whether or not a ticket exists in the live ticket
// treap of the best node.
Expand Down
35 changes: 22 additions & 13 deletions internal/rpcserver/rpcserverhandlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/decred/dcrd/internal/mempool"
"github.com/decred/dcrd/internal/mining"
"github.com/decred/dcrd/internal/version"
"github.com/decred/dcrd/math/uint256"
"github.com/decred/dcrd/peer/v3"
"github.com/decred/dcrd/rpc/jsonrpc/types/v4"
"github.com/decred/dcrd/txscript/v4"
Expand Down Expand Up @@ -144,7 +145,7 @@ type testRPCChain struct {
blockHeightByHashErr error
calcWantHeight int64
chainTips []blockchain.ChainTipInfo
chainWork *big.Int
chainWork uint256.Uint256
chainWorkErr error
checkLiveTicket bool
checkLiveTickets []bool
Expand Down Expand Up @@ -241,7 +242,7 @@ func (c *testRPCChain) ChainTips() []blockchain.ChainTipInfo {

// ChainWork returns returns a mocked total work up to and including the block
// of the provided block hash.
func (c *testRPCChain) ChainWork(hash *chainhash.Hash) (*big.Int, error) {
func (c *testRPCChain) ChainWork(hash *chainhash.Hash) (uint256.Uint256, error) {
return c.chainWork, c.chainWorkErr
}

Expand Down Expand Up @@ -1272,6 +1273,19 @@ func hexToBytes(s string) []byte {
return b
}

// hexToUint256 interprets the passed hex string as a 256-bit big-endian
// unsigned integer and returns the resulting uint256. It will panic if there
// is an error. This is only provided for the hard-coded constants so errors in
// the source code can be detected. It will only (and must only) be called with
// hard-coded values.
func hexToUint256(s string) uint256.Uint256 {
b, err := hex.DecodeString(s)
if err != nil {
panic("invalid hex in source file: " + s)
}
return *new(uint256.Uint256).SetByteSlice(b)
}

// hexToMsgTx converts the passed hex string into a wire.MsgTx and will panic if
// there is an error. This is only provided for hard-coded constants so errors
// in the source code can be detected. It will only (and must only) be called
Expand Down Expand Up @@ -1416,7 +1430,7 @@ func defaultMockRPCChain() *testRPCChain {
headerByHashFn := func() wire.BlockHeader { return blkHeader }
blkHash := blk.Hash()
blkHeight := blk.Height()
chainWork, _ := new(big.Int).SetString("0e805fb85284503581c57c", 16)
chainWork := hexToUint256("0e805fb85284503581c57c")
return &testRPCChain{
bestSnapshot: &blockchain.BestState{
Hash: *blkHash,
Expand Down Expand Up @@ -3579,8 +3593,7 @@ func TestHandleGetBlockchainInfo(t *testing.T) {
}
chain.bestHeaderHash = *hash
chain.bestHeaderHeight = 463073
chain.chainWork = big.NewInt(0).SetBytes([]byte{0x11, 0x5d, 0x28, 0x33, 0x84,
0x90, 0x90, 0xb0, 0x02, 0x65, 0x06})
chain.chainWork = hexToUint256("115d2833849090b0026506")
chain.isCurrent = false
chain.maxBlockSize = 393216
chain.stateLastChangedHeight = int64(149248)
Expand Down Expand Up @@ -3619,8 +3632,7 @@ func TestHandleGetBlockchainInfo(t *testing.T) {
Hash: *genesisHash,
PrevHash: *genesisPrevHash,
}
chain.chainWork = big.NewInt(0).SetBytes([]byte{0x80, 0x00, 0x40, 0x00, 0x20,
0x00})
chain.chainWork = hexToUint256("800040002000")
chain.isCurrent = false
chain.maxBlockSize = 393216
chain.nextThresholdState = blockchain.ThresholdStateTuple{
Expand Down Expand Up @@ -3681,8 +3693,7 @@ func TestHandleGetBlockchainInfo(t *testing.T) {
Hash: *hash,
PrevHash: *prevHash,
}
chain.chainWork = big.NewInt(0).SetBytes([]byte{0x11, 0x5d, 0x28, 0x33, 0x84,
0x90, 0x90, 0xb0, 0x02, 0x65, 0x06})
chain.chainWork = hexToUint256("115d2833849090b0026506")
chain.maxBlockSizeErr = errors.New("could not fetch max block size")
return chain
}(),
Expand All @@ -3700,8 +3711,7 @@ func TestHandleGetBlockchainInfo(t *testing.T) {
Hash: *hash,
PrevHash: *prevHash,
}
chain.chainWork = big.NewInt(0).SetBytes([]byte{0x11, 0x5d, 0x28, 0x33, 0x84,
0x90, 0x90, 0xb0, 0x02, 0x65, 0x06})
chain.chainWork = hexToUint256("115d2833849090b0026506")
chain.maxBlockSize = 393216
chain.nextThresholdStateErr = errors.New("could not fetch threshold state")
return chain
Expand All @@ -3720,8 +3730,7 @@ func TestHandleGetBlockchainInfo(t *testing.T) {
Hash: *hash,
PrevHash: *prevHash,
}
chain.chainWork = big.NewInt(0).SetBytes([]byte{0x11, 0x5d, 0x28, 0x33, 0x84,
0x90, 0x90, 0xb0, 0x02, 0x65, 0x06})
chain.chainWork = hexToUint256("115d2833849090b0026506")
chain.maxBlockSize = 393216
chain.stateLastChangedHeightErr = errors.New("could not fetch state last changed")
return chain
Expand Down

0 comments on commit b406a77

Please sign in to comment.