Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lockup flag, API and bugfixes #2288

Merged
merged 4 commits into from
Oct 25, 2024
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
15 changes: 15 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ var NodeFlags = []Flag{
QuaiCoinbaseFlag,
QiCoinbaseFlag,
MinerPreferenceFlag,
CoinbaseLockupFlag,
EnvironmentFlag,
QuaiStatsURLFlag,
SendFullStatsFlag,
Expand Down Expand Up @@ -531,6 +532,12 @@ var (
Usage: "Indicates preference towards mining Quai or Qi. Any value between 0 and 1 is valid. Neutral: 0.5, Quai only: 0, Qi only: 1" + generateEnvDoc(c_NodeFlagPrefix+"miner-preference"),
}

CoinbaseLockupFlag = Flag{
Name: c_NodeFlagPrefix + "coinbase-lockup",
Value: 0,
Usage: "Lockup byte used to determine the number of blocks that coinbase rewards are locked for" + generateEnvDoc(c_NodeFlagPrefix+"coinbase-lockup"),
}

IndexAddressUtxos = Flag{
Name: c_NodeFlagPrefix + "index-address-utxos",
Value: false,
Expand Down Expand Up @@ -1386,6 +1393,14 @@ func SetQuaiConfig(stack *node.Node, cfg *quaiconfig.Config, slicesRunning []com
cfg.Miner.MinerPreference = minerPreference
}

coinbaseLockup := viper.GetUint64(CoinbaseLockupFlag.Name)
if coinbaseLockup < 0 || coinbaseLockup > uint64(len(params.LockupByteToBlockDepth))-1 {
log.Global.WithField("CoinbaseLockup", coinbaseLockup).Error("Invalid CoinbaseLockup field. Must be [0,3]. Setting to default value 0")
cfg.Miner.CoinbaseLockup = params.DefaultCoinbaseLockup
} else {
cfg.Miner.CoinbaseLockup = uint8(coinbaseLockup)
}

// Override any default configs for hard coded networks.
switch viper.GetString(EnvironmentFlag.Name) {
case params.ColosseumName:
Expand Down
8 changes: 8 additions & 0 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,14 @@ func (c *Core) SetSecondaryCoinbase(addr common.Address) {
c.sl.miner.SetSecondaryCoinbase(addr)
}

func (c *Core) SetLockupByte(lockupByte uint8) {
c.sl.miner.worker.SetLockupByte(lockupByte)
}

func (c *Core) SetMinerPreference(minerPreference float64) {
c.sl.miner.worker.SetMinerPreference(minerPreference)
}

// SubscribePendingLogs starts delivering logs from pending transactions
// to the given channel.
func (c *Core) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription {
Expand Down
2 changes: 1 addition & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func (p *StateProcessor) Process(block *types.WorkObject, batch ethdb.Batch) (ty
}
lockupByte := tx.Data()[0]
if tx.To().IsInQiLedgerScope() {
if int(lockupByte) > len(params.LockupByteToBlockDepth) {
if int(lockupByte) > len(params.LockupByteToBlockDepth)-1 {
return nil, nil, nil, nil, 0, 0, 0, nil, nil, fmt.Errorf("coinbase lockup byte %d is out of range", lockupByte)
}
lockup := new(big.Int).SetUint64(params.LockupByteToBlockDepth[lockupByte])
Expand Down
50 changes: 42 additions & 8 deletions core/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ const (
chainSideChanSize = 10

c_uncleCacheSize = 100

defaultCoinbaseLockup = 0
)

// environment is the worker's current environment and holds all
Expand Down Expand Up @@ -104,6 +102,7 @@ func (env *environment) unclelist() []*types.WorkObjectHeader {
type Config struct {
QuaiCoinbase common.Address `toml:",omitempty"` // Public address for Quai mining rewards
QiCoinbase common.Address `toml:",omitempty"` // Public address for Qi mining rewards
CoinbaseLockup uint8 `toml:",omitempty"` // Lockup byte the determines number of blocks before mining rewards can be spent
MinerPreference float64 // Determines the relative preference of Qi or Quai [0, 1] respectively
Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash).
NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages
Expand Down Expand Up @@ -161,6 +160,8 @@ type worker struct {
qiCoinbase common.Address
primaryCoinbase common.Address
secondaryCoinbase common.Address
coinbaseLockup uint8
minerPreference float64
extra []byte

workerDb ethdb.Database
Expand Down Expand Up @@ -235,6 +236,12 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, db ethdb.Databas
resubmitIntervalCh: make(chan time.Duration),
fillTransactionsRollingAverage: &RollingAverage{windowSize: 100},
logger: logger,
coinbaseLockup: config.CoinbaseLockup,
minerPreference: config.MinerPreference,
}
if worker.coinbaseLockup > uint8(len(params.LockupByteToBlockDepth))-1 {
logger.Errorf("Invalid coinbase lockup value %d, using default value %d", worker.coinbaseLockup, params.DefaultCoinbaseLockup)
worker.coinbaseLockup = params.DefaultCoinbaseLockup
}
// initialize a uncle cache
uncles, _ := lru.New[common.Hash, types.WorkObjectHeader](c_uncleCacheSize)
Expand Down Expand Up @@ -281,7 +288,7 @@ func (w *worker) pickCoinbases() {
defer w.mu.Unlock()

// Use the MinerPreference to bias the decision
if rand.Float64() > w.config.MinerPreference {
if rand.Float64() > w.minerPreference {
// if MinerPreference < 0.5, bias is towards Quai
w.primaryCoinbase = w.quaiCoinbase
w.secondaryCoinbase = w.qiCoinbase
Expand Down Expand Up @@ -320,6 +327,32 @@ func (w *worker) GetSecondaryCoinbase() common.Address {
return w.secondaryCoinbase
}

func (w *worker) SetMinerPreference(preference float64) {
w.mu.Lock()
defer w.mu.Unlock()
w.minerPreference = preference
}

func (w *worker) GetMinerPreference() float64 {
w.mu.RLock()
defer w.mu.RUnlock()
return w.minerPreference
}

func (w *worker) GetLockupByte() uint8 {
w.mu.RLock()
defer w.mu.RUnlock()

return w.coinbaseLockup
}

func (w *worker) SetLockupByte(lockupByte uint8) {
w.mu.Lock()
defer w.mu.Unlock()

w.coinbaseLockup = lockupByte
}

func (w *worker) setGasCeil(ceil uint64) {
w.mu.Lock()
defer w.mu.Unlock()
Expand Down Expand Up @@ -598,29 +631,30 @@ func (w *worker) GeneratePendingHeader(block *types.WorkObject, fill bool, txs t
if err != nil {
return nil, err
}
lockupByte := work.wo.Lock()

// If the primary coinbase belongs to a ledger and there is no fees
// for other ledger, there is no etxs emitted for the other ledger
if bytes.Equal(work.wo.PrimaryCoinbase().Bytes(), quaiCoinbase.Bytes()) {
coinbaseReward := misc.CalculateReward(block, work.wo.WorkObjectHeader())
blockReward := new(big.Int).Add(coinbaseReward, work.quaiFees)
primaryCoinbase := w.GetPrimaryCoinbase()
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &primaryCoinbase, Gas: params.TxGas, Value: blockReward, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQuai(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: primaryCoinbase, Data: []byte{defaultCoinbaseLockup}})
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &primaryCoinbase, Gas: params.TxGas, Value: blockReward, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQuai(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: primaryCoinbase, Data: []byte{lockupByte}})
work.etxs = append(work.etxs, coinbaseEtx)
if work.utxoFees.Cmp(big.NewInt(0)) != 0 {
secondaryCoinbase := w.GetSecondaryCoinbase()
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &secondaryCoinbase, Gas: params.TxGas, Value: work.utxoFees, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQi(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: w.secondaryCoinbase, Data: []byte{defaultCoinbaseLockup}})
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &secondaryCoinbase, Gas: params.TxGas, Value: work.utxoFees, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQi(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: w.secondaryCoinbase, Data: []byte{lockupByte}})
work.etxs = append(work.etxs, coinbaseEtx)
}
} else if bytes.Equal(work.wo.PrimaryCoinbase().Bytes(), qiCoinbase.Bytes()) {
coinbaseReward := misc.CalculateReward(block, work.wo.WorkObjectHeader())
blockReward := new(big.Int).Add(coinbaseReward, work.utxoFees)
primaryCoinbase := w.GetPrimaryCoinbase()
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &primaryCoinbase, Gas: params.TxGas, Value: blockReward, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQi(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: primaryCoinbase, Data: []byte{defaultCoinbaseLockup}})
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &primaryCoinbase, Gas: params.TxGas, Value: blockReward, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQi(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: primaryCoinbase, Data: []byte{lockupByte}})
work.etxs = append(work.etxs, coinbaseEtx)
if work.quaiFees.Cmp(big.NewInt(0)) != 0 {
secondaryCoinbase := w.GetSecondaryCoinbase()
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &secondaryCoinbase, Gas: params.TxGas, Value: work.quaiFees, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQuai(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: secondaryCoinbase, Data: []byte{defaultCoinbaseLockup}})
coinbaseEtx := types.NewTx(&types.ExternalTx{To: &secondaryCoinbase, Gas: params.TxGas, Value: work.quaiFees, EtxType: types.CoinbaseType, OriginatingTxHash: common.SetBlockHashForQuai(block.Hash(), w.hc.NodeLocation()), ETXIndex: uint16(len(work.etxs)), Sender: secondaryCoinbase, Data: []byte{lockupByte}})
work.etxs = append(work.etxs, coinbaseEtx)
}
}
Expand Down Expand Up @@ -1427,7 +1461,7 @@ func (w *worker) prepareWork(genParams *generateParams, wo *types.WorkObject) (*
// Construct the sealing block header, set the extra field if it's allowed
num := parent.Number(nodeCtx)
newWo := types.EmptyWorkObject(nodeCtx)
newWo.WorkObjectHeader().SetLock(defaultCoinbaseLockup)
newWo.WorkObjectHeader().SetLock(w.GetLockupByte())
newWo.SetParentHash(wo.Hash(), nodeCtx)
if w.hc.IsGenesisHash(parent.Hash()) {
newWo.SetNumber(big.NewInt(1), nodeCtx)
Expand Down
8 changes: 4 additions & 4 deletions internal/quaiapi/quai_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ func (s *PublicBlockChainQuaiAPI) GetProtocolExpansionNumber() hexutil.Uint {
}

// Calculate the amount of Quai that Qi can be converted to. Expect the current Header and the Qi amount in "qits", returns the quai amount in "its"
func (s *PublicBlockChainQuaiAPI) QiRateAtBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, qiAmount uint64) *hexutil.Big {
func (s *PublicBlockChainQuaiAPI) QiRateAtBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, qiAmount hexutil.Big) *hexutil.Big {
var header *types.WorkObject
var err error
if blockNr, ok := blockNrOrHash.Number(); ok {
Expand All @@ -852,11 +852,11 @@ func (s *PublicBlockChainQuaiAPI) QiRateAtBlock(ctx context.Context, blockNrOrHa
} else if header == nil {
return nil
}
return (*hexutil.Big)(misc.QiToQuai(header, new(big.Int).SetUint64(qiAmount)))
return (*hexutil.Big)(misc.QiToQuai(header, qiAmount.ToInt()))
}

// Calculate the amount of Qi that Quai can be converted to. Expect the current Header and the Quai amount in "its", returns the Qi amount in "qits"
func (s *PublicBlockChainQuaiAPI) QuaiRateAtBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, quaiAmount uint64) *hexutil.Big {
func (s *PublicBlockChainQuaiAPI) QuaiRateAtBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, quaiAmount hexutil.Big) *hexutil.Big {
var header *types.WorkObject
var err error
if blockNr, ok := blockNrOrHash.Number(); ok {
Expand All @@ -876,7 +876,7 @@ func (s *PublicBlockChainQuaiAPI) QuaiRateAtBlock(ctx context.Context, blockNrOr
} else if header == nil {
return nil
}
return (*hexutil.Big)(misc.QuaiToQi(header, new(big.Int).SetUint64(quaiAmount)))
return (*hexutil.Big)(misc.QuaiToQi(header, quaiAmount.ToInt()))
}

func (s *PublicBlockChainQuaiAPI) CalcOrder(ctx context.Context, raw hexutil.Bytes) (hexutil.Uint, error) {
Expand Down
3 changes: 2 additions & 1 deletion params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ const (
ConversionLockPeriod uint64 = 10 // The number of zone blocks that a conversion output is locked for
MinQiConversionDenomination = 10
ConversionConfirmationContext = common.PRIME_CTX // A conversion requires a single coincident Dom confirmation
SoftMaxUTXOSetSize = 10000000 // The soft maximum number of UTXOs that can be stored in the UTXO set
SoftMaxUTXOSetSize = math.MaxInt // The soft maximum number of UTXOs that can be stored in the UTXO set
MinimumTrimDepth = math.MaxInt // The minimum block depth of the chain to begin trimming
QiToQuaiConversionGas = 100000 // The gas used to convert Qi to Quai
DefaultCoinbaseLockup = 0 // The default lockup byte for coinbase rewards
)

var (
Expand Down
22 changes: 22 additions & 0 deletions quai/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"io"
"math/big"
"os"
"strconv"
"strings"
"time"

Expand All @@ -33,6 +34,7 @@ import (
"github.com/dominant-strategies/go-quai/core/rawdb"
"github.com/dominant-strategies/go-quai/core/state"
"github.com/dominant-strategies/go-quai/core/types"
"github.com/dominant-strategies/go-quai/params"
"github.com/dominant-strategies/go-quai/rlp"
"github.com/dominant-strategies/go-quai/rpc"
"github.com/dominant-strategies/go-quai/trie"
Expand Down Expand Up @@ -117,6 +119,26 @@ func (api *PrivateMinerAPI) SetSecondaryCoinbase(secondaryCoinbase common.Addres
return true
}

func (api *PrivateMinerAPI) SetLockupByte(lockupByte hexutil.Uint64) (bool, error) {
if uint8(lockupByte) > uint8(len(params.LockupByteToBlockDepth)-1) {
return false, fmt.Errorf("lockup byte %d out of range", lockupByte)
}
api.e.Core().SetLockupByte(uint8(lockupByte))
return true, nil
}

func (api *PrivateMinerAPI) SetMinerPreference(minerPreference string) (bool, error) {
preferenceFloat, err := strconv.ParseFloat(minerPreference, 64)
if err != nil {
return false, err
}
if preferenceFloat < 0 || preferenceFloat > 1 {
return false, errors.New("miner preference must be between 0 and 1")
}
api.e.Core().SetMinerPreference(preferenceFloat)
return true, nil
}

// SetRecommitInterval updates the interval for miner sealing work recommitting.
func (api *PrivateMinerAPI) SetRecommitInterval(interval int) {
api.e.Core().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
Expand Down
Loading