Skip to content
This repository has been archived by the owner on Mar 8, 2024. It is now read-only.

add genesis utxos for testing #125

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
36 changes: 18 additions & 18 deletions cmd/utils/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,25 @@ func StartQuaiBackend(ctx context.Context, p2p quai.NetworkingAPI, logLevel stri
// Set the p2p backend inside the quaiBackend
quaiBackend.SetP2PApiBackend(p2p)

slicesRunning := getSlicesRunning()
regionsRunning := getRegionsRunning(slicesRunning)
runningSlices := GetRunningZones()
runningRegions := GetRunningRegions(runningSlices)

// Start nodes in separate goroutines
startNode("nodelogs/prime.log", nil, slicesRunning)
for _, region := range regionsRunning {
startNode("nodelogs/prime.log", nil, runningSlices)
for _, region := range runningRegions {
nodelogsFileName := "nodelogs/region-" + fmt.Sprintf("%d", region) + ".log"
startNode(nodelogsFileName, common.Location{region}, slicesRunning)
startNode(nodelogsFileName, common.Location{region}, runningSlices)
}
for _, slice := range slicesRunning {
for _, slice := range runningSlices {
nodelogsFileName := "nodelogs/zone-" + fmt.Sprintf("%d", slice[0]) + "-" + fmt.Sprintf("%d", slice[1]) + ".log"
startNode(nodelogsFileName, slice, slicesRunning)
startNode(nodelogsFileName, slice, runningSlices)
}

return quaiBackend, nil
}

// setSlicesRunning sets the slices running flag
func getSlicesRunning() []common.Location {
// GetRunningZones returns the slices that are processing state (which are only zones)
func GetRunningZones() []common.Location {
slices := strings.Split(viper.GetString(SlicesRunningFlag.Name), ",")

// Sanity checks
Expand All @@ -86,22 +86,22 @@ func getSlicesRunning() []common.Location {
if len(slices) > common.NumRegionsInPrime*common.NumZonesInRegion {
Fatalf("number of slices exceed the current ontology")
}
slicesRunning := []common.Location{}
runningSlices := []common.Location{}
for _, slice := range slices {
slicesRunning = append(slicesRunning, common.Location{slice[1] - 48, slice[3] - 48})
runningSlices = append(runningSlices, common.Location{slice[1] - 48, slice[3] - 48})
}
return slicesRunning
return runningSlices
}

// getRegionsRunning returns the regions running
func getRegionsRunning(slicesRunning []common.Location) []byte {
regionsRunning := []byte{}
for _, slice := range slicesRunning {
if !slices.Contains(regionsRunning, slice[0]) {
regionsRunning = append(regionsRunning, slice[0])
func GetRunningRegions(runningSlices []common.Location) []byte {
runningRegions := []byte{}
for _, slice := range runningSlices {
if !slices.Contains(runningRegions, slice[0]) {
runningRegions = append(runningRegions, slice[0])
}
}
return regionsRunning
return runningRegions
}

func StartNode(stack *node.Node) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ func setSubUrls(cfg *quaiconfig.Config, nodeLocation common.Location) {
switch nodeLocation.Context() {
case common.PRIME_CTX:
subUrls := []string{}
regionsRunning := getRegionsRunning(slicesRunning)
regionsRunning := GetRunningRegions(slicesRunning)
for _, region := range regionsRunning {
subUrls = append(subUrls, fmt.Sprintf("ws://127.0.0.1:%d", 8002+int(region)))
}
Expand Down
10 changes: 4 additions & 6 deletions common/stream_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,15 @@ func WriteMessageToStream(stream network.Stream, msg []byte) error {
return errors.Wrap(err, "failed to set write deadline")
}

// Get the length of the message and convert it into 4 bytes
// Get the length of the message and encode it
msgLen := uint32(len(msg))
lenBytes := make([]byte, 4)
binary.BigEndian.PutUint32(lenBytes, msgLen)

// First write the length of the message
if _, err := stream.Write(lenBytes); err != nil {
return errors.Wrap(err, "failed to write message length to stream")
}
// Prefix the message with the encoded length
msg = append(lenBytes, msg...)

// Then write the message itself
// Then write the message
_, err := stream.Write(msg)
if err != nil {
return errors.Wrap(err, "failed to write message to stream")
Expand Down
19 changes: 19 additions & 0 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,25 @@ func (loc Location) SubInSlice(slice Location) Location {
return subLoc
}

// GetDoms returns the dom locations that must be running for a given location
// For example:
// - if a region-0 calls GetDoms() the result will be
// [prime, region-0]
// - if a zone-0-0 calls GetDoms() the result will be
// [prime, region-0, zone-0-0]
func (loc Location) GetDoms() []Location {
var dominantLocations []Location

// Always start with the prime location
dominantLocations = append(dominantLocations, Location{})

for i := range loc {
dominantLocations = append(dominantLocations, loc[:i+1])
}

return dominantLocations
}

func (loc Location) InSameSliceAs(cmp Location) bool {
// Figure out which location is shorter
shorter := loc
Expand Down
2 changes: 2 additions & 0 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ func (blake3pow *Blake3pow) Finalize(chain consensus.ChainHeaderReader, header *
continue
}
}

core.AddGenesisUtxos(state, nodeLocation, blake3pow.logger)
}
header.SetUTXORoot(state.UTXORoot())
header.SetEVMRoot(state.IntermediateRoot(true))
Expand Down
21 changes: 2 additions & 19 deletions consensus/misc/rewards.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,8 @@ func calculateQiReward(header *types.Header) *big.Int {
return big.NewInt(1000)
}

func CalculateRewardForQi(header *types.Header) map[uint8]uint8 {
rewardFromDifficulty := new(big.Int).Add(types.Denominations[types.MaxDenomination], types.Denominations[10])
return findMinDenominations(rewardFromDifficulty)
}

func CalculateRewardForQiWithFees(header *types.Header, fees *big.Int) map[uint8]uint8 {
rewardFromDifficulty := new(big.Int).Add(types.Denominations[types.MaxDenomination], types.Denominations[10])
reward := new(big.Int).Add(rewardFromDifficulty, fees)
return findMinDenominations(reward)
}

func CalculateRewardForQiWithFeesBigInt(header *types.Header, fees *big.Int) *big.Int {
rewardFromDifficulty := new(big.Int).Add(types.Denominations[types.MaxDenomination], types.Denominations[10])
reward := new(big.Int).Add(rewardFromDifficulty, fees)
return reward
}

// findMinDenominations finds the minimum number of denominations to make up the reward
func findMinDenominations(reward *big.Int) map[uint8]uint8 {
// FindMinDenominations finds the minimum number of denominations to make up the reward
func FindMinDenominations(reward *big.Int) map[uint8]uint8 {
// Store the count of each denomination used (map denomination to count)
denominationCount := make(map[uint8]uint8)
amount := new(big.Int).Set(reward)
Expand Down
1 change: 1 addition & 0 deletions consensus/progpow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ func (progpow *Progpow) Finalize(chain consensus.ChainHeaderReader, header *type
continue
}
}
core.AddGenesisUtxos(state, nodeLocation, progpow.logger)
}
header.SetUTXORoot(state.UTXORoot())
header.SetEVMRoot(state.IntermediateRoot(true))
Expand Down
59 changes: 59 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ type GenesisAccount struct {
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
}

type GenesisUTXO struct {
Denomination uint32 `json:"denomination"`
Index uint32 `json:"index"`
Hash string `json:"hash"`
}

// field type overrides for gencodec
type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64
Expand Down Expand Up @@ -467,3 +473,56 @@ func ReadGenesisAlloc(filename string, logger *log.Logger) map[string]GenesisAcc
// Use the parsed data
return data
}

func ReadGenesisQiAlloc(filename string, logger *log.Logger) map[string]GenesisUTXO {
jsonFile, err := os.Open(filename)
if err != nil {
logger.Error(err.Error())
return nil
}
defer jsonFile.Close()
// Read the file contents
byteValue, err := ioutil.ReadAll(jsonFile)
if err != nil {
logger.Error(err.Error())
return nil
}

// Parse the JSON data
var data map[string]GenesisUTXO
err = json.Unmarshal(byteValue, &data)
if err != nil {
logger.Error(err.Error())
return nil
}

// Use the parsed data
return data
}

// WriteGenesisUtxoSet writes the genesis utxo set to the database
func AddGenesisUtxos(state *state.StateDB, nodeLocation common.Location, logger *log.Logger) {
qiAlloc := ReadGenesisQiAlloc("genallocs/gen_alloc_qi_"+nodeLocation.Name()+".json", logger)
// logger.WithField("alloc", len(qiAlloc)).Info("Allocating genesis accounts")
for addressString, utxo := range qiAlloc {
addr := common.HexToAddress(addressString, nodeLocation)
internal, err := addr.InternalAddress()
if err != nil {
logger.Error("Provided address in genesis block is out of scope")
}

hash := common.HexToHash(utxo.Hash)

// check if utxo.Denomination is less than uint8
if utxo.Denomination > 255 {
logger.Error("Provided denomination is larger than uint8")
}

newUtxo := &types.UtxoEntry{
Address: internal.Bytes(),
Denomination: uint8(utxo.Denomination),
}

state.CreateUTXO(hash, uint16(utxo.Index), newUtxo)
}
}
23 changes: 18 additions & 5 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (p *StateProcessor) Process(block *types.Block, etxSet types.EtxSet) (types
// coinbase tx currently exempt from gas and outputs are added after all txs are processed
continue
}
fees, etxs, err := ProcessQiTx(tx, true, statedb, gp, usedGas, p.hc.pool.signer, p.hc.NodeLocation(), *p.config.ChainID, &etxRLimit, &etxPLimit)
fees, etxs, err := ProcessQiTx(tx, true, header, statedb, gp, usedGas, p.hc.pool.signer, p.hc.NodeLocation(), *p.config.ChainID, &etxRLimit, &etxPLimit)
if err != nil {
return nil, nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
Expand Down Expand Up @@ -342,7 +342,9 @@ func (p *StateProcessor) Process(block *types.Block, etxSet types.EtxSet) (types
for _, txOut := range qiTransactions[0].TxOut() {
totalCoinbaseOut.Add(totalCoinbaseOut, types.Denominations[txOut.Denomination])
}
maxCoinbaseOut := misc.CalculateRewardForQiWithFeesBigInt(header, totalFees) // TODO: Miner tip will soon no longer exist
reward := misc.CalculateReward(header)
maxCoinbaseOut := new(big.Int).Add(reward, totalFees) // TODO: Miner tip will soon no longer exist

if totalCoinbaseOut.Cmp(maxCoinbaseOut) > 0 {
return nil, nil, nil, nil, 0, fmt.Errorf("coinbase output value of %v is higher than expected value of %v", totalCoinbaseOut, maxCoinbaseOut)
}
Expand Down Expand Up @@ -462,14 +464,17 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
return receipt, err
}

func ProcessQiTx(tx *types.Transaction, updateState bool, statedb *state.StateDB, gp *GasPool, usedGas *uint64, signer types.Signer, location common.Location, chainId big.Int, etxRLimit, etxPLimit *int) (*big.Int, []*types.Transaction, error) {
func ProcessQiTx(tx *types.Transaction, updateState bool, currentHeader *types.Header, statedb *state.StateDB, gp *GasPool, usedGas *uint64, signer types.Signer, location common.Location, chainId big.Int, etxRLimit, etxPLimit *int) (*big.Int, []*types.Transaction, error) {
// Sanity checks
if tx.Type() != types.QiTxType {
if tx == nil || tx.Type() != types.QiTxType {
return nil, nil, fmt.Errorf("tx %032x is not a QiTx", tx.Hash())
}
if tx.ChainId().Cmp(&chainId) != 0 {
return nil, nil, fmt.Errorf("tx %032x has invalid chain ID", tx.Hash())
}
if currentHeader == nil || statedb == nil || gp == nil || usedGas == nil || signer == nil || etxRLimit == nil || etxPLimit == nil {
return nil, nil, errors.New("one of the parameters is nil")
}

addresses := make(map[common.AddressBytes]struct{})

Expand Down Expand Up @@ -603,8 +608,16 @@ func ProcessQiTx(tx *types.Transaction, updateState bool, statedb *state.StateDB
return nil, nil, errors.New("invalid signature for digest hash " + txDigestHash.String())
}
// the fee to pay the basefee/miner is the difference between inputs and outputs
// We should enforce the Qi-converted-basefee here
txFeeInQit := new(big.Int).Sub(totalQitIn, totalQitOut)
// Check tx against required base fee and gas
baseFeeInQi := misc.QuaiToQi(currentHeader, currentHeader.BaseFee())
minimumFee := new(big.Int).Mul(baseFeeInQi, big.NewInt(int64(txGas)))
if txFeeInQit.Cmp(minimumFee) < 0 {
return nil, nil, fmt.Errorf("tx %032x has insufficient fee for base fee of %d and gas of %d", tx.Hash(), baseFeeInQi.Uint64(), txGas)
}
// Miner gets remainder of fee after base fee
txFeeInQit.Sub(txFeeInQit, minimumFee)

*etxRLimit -= ETXRCount
*etxPLimit -= ETXPCount
return txFeeInQit, etxs, nil
Expand Down
35 changes: 20 additions & 15 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ type TxPool struct {

locals *accountSet // Set of local transaction to exempt from eviction rules
journal *txJournal // Journal of local transaction to back up to disk
utxoPool map[common.Hash]*types.QiTxWithMinerFee // Utxo pool to store utxo transactions
utxoPool map[common.Hash]*types.TxWithMinerFee // Utxo pool to store utxo transactions
pending map[common.InternalAddress]*txList // All currently processable transactions
queue map[common.InternalAddress]*txList // Queued but non-processable transactions
beats map[common.InternalAddress]time.Time // Last heartbeat from each known account
Expand Down Expand Up @@ -345,7 +345,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
chain: chain,
signer: types.LatestSigner(chainconfig),
pending: make(map[common.InternalAddress]*txList),
utxoPool: make(map[common.Hash]*types.QiTxWithMinerFee),
utxoPool: make(map[common.Hash]*types.TxWithMinerFee),
queue: make(map[common.InternalAddress]*txList),
beats: make(map[common.InternalAddress]time.Time),
senders: orderedmap.New[common.Hash, common.InternalAddress](),
Expand Down Expand Up @@ -593,11 +593,15 @@ func (pool *TxPool) ContentFrom(addr common.InternalAddress) (types.Transactions
return pending, queued
}

func (pool *TxPool) UTXOPoolPending() map[common.Hash]*types.QiTxWithMinerFee {
func (pool *TxPool) UTXOPoolPending() map[common.Hash]*types.TxWithMinerFee {
pool.utxoMu.RLock()
defer pool.utxoMu.RUnlock()
// to do: check fees
return pool.utxoPool
// Return a copy of the pool because it is not safe to access the pool pointer directly
qiTxs := make(map[common.Hash]*types.TxWithMinerFee)
for hash, qiTx := range pool.utxoPool {
qiTxs[hash] = qiTx
}
return qiTxs
}

// Pending retrieves all currently processable transactions, grouped by origin
Expand Down Expand Up @@ -1040,8 +1044,12 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
errs[i] = err
}
continue
} else if tx.Type() == types.InternalToExternalTxType && tx.To() == nil {
errs[i] = errors.New("to address is nil in InternalToExternalTx") // remove this check when InternalToExternalTx is removed
invalidTxMeter.Add(1)
continue
}
if tx.To().IsInQiLedgerScope() {
if tx.To() != nil && tx.To().IsInQiLedgerScope() {
errs[i] = common.MakeErrQiAddress(tx.To().Hex())
invalidTxMeter.Add(1)
continue
Expand Down Expand Up @@ -1072,12 +1080,6 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
invalidTxMeter.Add(1)
continue
}
_, err = types.Sender(pool.signer, tx)
if err != nil {
errs[i] = ErrInvalidSender
invalidTxMeter.Add(1)
continue
}
}

// Accumulate all unknown transactions for deeper processing
Expand Down Expand Up @@ -1129,7 +1131,7 @@ func (pool *TxPool) addUtxoTx(tx *types.Transaction) error {
etxPLimit = params.ETXPLimitMin
}
pool.mu.RLock() // need to readlock the whole pool because we are reading the current state
fee, _, err := ProcessQiTx(tx, false, pool.currentState, &gp, new(uint64), pool.signer, location, *pool.chainconfig.ChainID, &etxRLimit, &etxPLimit)
fee, _, err := ProcessQiTx(tx, false, pool.chain.CurrentBlock().Header(), pool.currentState, &gp, new(uint64), pool.signer, location, *pool.chainconfig.ChainID, &etxRLimit, &etxPLimit)
if err != nil {
pool.mu.RUnlock()
pool.logger.WithFields(logrus.Fields{
Expand All @@ -1139,9 +1141,12 @@ func (pool *TxPool) addUtxoTx(tx *types.Transaction) error {
return err
}
pool.mu.RUnlock()

txWithMinerFee, err := types.NewTxWithMinerFee(tx, nil, fee)
if err != nil {
return err
}
pool.utxoMu.Lock()
pool.utxoPool[tx.Hash()] = &types.QiTxWithMinerFee{tx, fee}
pool.utxoPool[tx.Hash()] = txWithMinerFee
pool.utxoMu.Unlock()
pool.logger.WithFields(logrus.Fields{
"tx": tx.Hash().String(),
Expand Down
2 changes: 1 addition & 1 deletion core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ func (b *Block) QiTransactions() []*Transaction {
func (b *Block) QuaiTransactions() []*Transaction {
quaiTxs := make([]*Transaction, 0)
for _, t := range b.Transactions() {
if t.Type() != QiTxType && t.To().IsInQuaiLedgerScope() {
if t.Type() != QiTxType && (t.To() == nil || t.To().IsInQuaiLedgerScope()) {
quaiTxs = append(quaiTxs, t)
}
}
Expand Down
Loading