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

Only generate pending header when we pick the head #2043

Closed
wants to merge 3 commits into from
Closed
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
5 changes: 5 additions & 0 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ func (blake3pow *Blake3pow) VerifyUncles(chain consensus.ChainReader, block *typ
return err
}

_, err = chain.WorkShareDistance(block, uncle)
if err != nil {
return err
}

// Verify the block's difficulty based on its timestamp and parent's difficulty
// difficulty adjustment can only be checked in zone
if nodeCtx == common.ZONE_CTX {
Expand Down
39 changes: 4 additions & 35 deletions consensus/blake3pow/poem.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,47 +196,16 @@ func (blake3pow *Blake3pow) WorkShareLogS(chain consensus.ChainHeaderReader, wo
} else {
wsEntropy = new(big.Int).Set(blake3pow.IntrinsicLogS(powHash))
}
var distance int64 = 0
// Discount 2) applies to all shares regardless of the weight
// a workshare cannot reference another workshare, it has to be either a block or an uncle
// check that the parent hash referenced by the workshare is an uncle or a canonical block
// then if its an uncle, traverse back until we hit a canonical block, other wise, use that
// as a reference to calculate the distance
parent := chain.GetBlockByHash(ws.ParentHash())
if parent == nil {
return big.NewInt(0), errors.New("error finding the parent of the work share")
}
// checking if the parent is an uncle
canonicalBlockForParentNum := chain.GetHeaderByNumber(parent.NumberU64(common.ZONE_CTX))
if canonicalBlockForParentNum == nil {
return big.NewInt(0), errors.New("cannot find a canonical block for the parent number")
}
// If this check passes, the parent block is not a canonical block, we have to trace back
if canonicalBlockForParentNum.Hash() != parent.Hash() {
var prevBlock *types.WorkObject
var uncleDist int64 = 0
for {
uncleDist++
prevBlock = chain.GetBlockByHash(parent.Hash())
if prevBlock == nil {
return big.NewInt(0), errors.New("cannot find a parent block of an uncle")
}
blockForPrevBlockNumber := chain.GetHeaderByNumber(prevBlock.NumberU64(common.ZONE_CTX))
if blockForPrevBlockNumber == nil {
return big.NewInt(0), errors.New("cannot find a canonical block for the uncle block number")
}
if prevBlock.Hash() == blockForPrevBlockNumber.Hash() {
break
}
if uncleDist > int64(params.WorkSharesInclusionDepth) {
return big.NewInt(0), errors.New("uncle referenced by the workshare is more than WorkShareInclusionDepth distance")
}
}
distance = int64(wo.NumberU64(common.ZONE_CTX)-prevBlock.NumberU64(common.ZONE_CTX)) + uncleDist - 1
} else {
distance = int64(wo.NumberU64(common.ZONE_CTX)-parent.NumberU64(common.ZONE_CTX)) - 1
distance, err := chain.WorkShareDistance(wo, ws)
if err != nil {
return big.NewInt(0), err
}
wsEntropy = new(big.Int).Div(wsEntropy, new(big.Int).Exp(big.NewInt(2), big.NewInt(distance), nil))
wsEntropy = new(big.Int).Div(wsEntropy, new(big.Int).Exp(big.NewInt(2), distance, nil))
// Add the entropy into the total entropy once the discount calculation is done
totalWsEntropy.Add(totalWsEntropy, wsEntropy)

Expand Down
4 changes: 4 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ type ChainHeaderReader interface {

// WriteAddressOutpoints writes the address outpoints to the database
WriteAddressOutpoints(outpointsMap map[string]map[string]*types.OutpointAndDenomination) error

// WorkShareDistance calculates the geodesic distance between the
// workshare and the workobject in which that workshare is included.
WorkShareDistance(wo *types.WorkObject, ws *types.WorkObjectHeader) (*big.Int, error)
}

// ChainReader defines a small collection of methods needed to access the local
Expand Down
5 changes: 5 additions & 0 deletions consensus/progpow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ func (progpow *Progpow) VerifyUncles(chain consensus.ChainReader, block *types.W
return err
}

_, err = chain.WorkShareDistance(block, uncle)
if err != nil {
return err
}

// Verify the block's difficulty based on its timestamp and parent's difficulty
// difficulty adjustment can only be checked in zone
if nodeCtx == common.ZONE_CTX {
Expand Down
39 changes: 4 additions & 35 deletions consensus/progpow/poem.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,47 +194,16 @@ func (progpow *Progpow) WorkShareLogS(chain consensus.ChainHeaderReader, wo *typ
} else {
wsEntropy = new(big.Int).Set(progpow.IntrinsicLogS(powHash))
}
var distance int64 = 0
// Discount 2) applies to all shares regardless of the weight
// a workshare cannot reference another workshare, it has to be either a block or an uncle
// check that the parent hash referenced by the workshare is an uncle or a canonical block
// then if its an uncle, traverse back until we hit a canonical block, other wise, use that
// as a reference to calculate the distance
parent := chain.GetBlockByHash(ws.ParentHash())
if parent == nil {
return big.NewInt(0), errors.New("error finding the parent of the work share")
}
// checking if the parent is an uncle
canonicalBlockForParentNum := chain.GetHeaderByNumber(parent.NumberU64(common.ZONE_CTX))
if canonicalBlockForParentNum == nil {
return big.NewInt(0), errors.New("cannot find a canonical block for the parent number")
}
// If this check passes, the parent block is not a canonical block, we have to trace back
if canonicalBlockForParentNum.Hash() != parent.Hash() {
var prevBlock *types.WorkObject
var uncleDist int64 = 0
for {
uncleDist++
prevBlock = chain.GetBlockByHash(parent.Hash())
if prevBlock == nil {
return big.NewInt(0), errors.New("cannot find a parent block of an uncle")
}
blockForPrevBlockNumber := chain.GetHeaderByNumber(prevBlock.NumberU64(common.ZONE_CTX))
if blockForPrevBlockNumber == nil {
return big.NewInt(0), errors.New("cannot find a canonical block for the uncle block number")
}
if prevBlock.Hash() == blockForPrevBlockNumber.Hash() {
break
}
if uncleDist > int64(params.WorkSharesInclusionDepth) {
return big.NewInt(0), errors.New("uncle referenced by the workshare is more than WorkShareInclusionDepth distance")
}
}
distance = int64(wo.NumberU64(common.ZONE_CTX)-prevBlock.NumberU64(common.ZONE_CTX)) + uncleDist - 1
} else {
distance = int64(wo.NumberU64(common.ZONE_CTX)-parent.NumberU64(common.ZONE_CTX)) - 1
distance, err := chain.WorkShareDistance(wo, ws)
if err != nil {
return big.NewInt(0), err
}
wsEntropy = new(big.Int).Div(wsEntropy, new(big.Int).Exp(big.NewInt(2), big.NewInt(distance), nil))
wsEntropy = new(big.Int).Div(wsEntropy, new(big.Int).Exp(big.NewInt(2), distance, nil))
// Add the entropy into the total entropy once the discount calculation is done
totalWsEntropy.Add(totalWsEntropy, wsEntropy)
}
Expand Down
6 changes: 6 additions & 0 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,12 @@ func (c *Core) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCano
return c.sl.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
}

// WorkShareDistance calculates the geodesic distance between the
// workshare and the workobject in which that workshare is included.
func (c *Core) WorkShareDistance(wo *types.WorkObject, ws *types.WorkObjectHeader) (*big.Int, error) {
return c.sl.hc.WorkShareDistance(wo, ws)
}

// Genesis retrieves the chain's genesis block.
func (c *Core) Genesis() *types.WorkObject {
return c.GetBlockByHash(c.sl.hc.genesisHeader.Hash())
Expand Down
114 changes: 69 additions & 45 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ func (hc *HeaderChain) AppendBlock(block *types.WorkObject) error {
func (hc *HeaderChain) SetCurrentHeader(head *types.WorkObject) error {
hc.headermu.Lock()
defer hc.headermu.Unlock()
nodeCtx := hc.NodeCtx()

prevHeader := hc.CurrentHeader()
// if trying to set the same header, escape
Expand All @@ -367,7 +368,13 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.WorkObject) error {
// If head is the normal extension of canonical head, we can return by just wiring the canonical hash.
if prevHeader.Hash() == head.ParentHash(hc.NodeCtx()) {
rawdb.WriteCanonicalHash(hc.headerDb, head.Hash(), head.NumberU64(hc.NodeCtx()))
return nil
if nodeCtx == common.ZONE_CTX {
err := hc.AppendBlock(head)
if err != nil {
return err
}
return nil
}
}

//Find a common header
Expand Down Expand Up @@ -411,6 +418,16 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.WorkObject) error {
// Run through the hash stack to update canonicalHash and forward state processor
for i := len(hashStack) - 1; i >= 0; i-- {
rawdb.WriteCanonicalHash(hc.headerDb, hashStack[i].Hash(), hashStack[i].NumberU64(hc.NodeCtx()))
if nodeCtx == common.ZONE_CTX {
block := hc.GetBlockOrCandidate(hashStack[i].Hash(), hashStack[i].NumberU64(nodeCtx))
if block == nil {
return errors.New("could not find block during SetCurrentState: " + hashStack[i].Hash().String())
}
err := hc.AppendBlock(block)
if err != nil {
return err
}
}
}

if hc.NodeCtx() == common.ZONE_CTX && hc.ProcessingState() {
Expand Down Expand Up @@ -439,50 +456,6 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.WorkObject) error {
return nil
}

// SetCurrentState updates the current Quai state and Qi UTXO set upon which the current pending block is built
func (hc *HeaderChain) SetCurrentState(head *types.WorkObject) error {
hc.headermu.Lock()
defer hc.headermu.Unlock()

nodeCtx := hc.NodeCtx()
if nodeCtx != common.ZONE_CTX || !hc.ProcessingState() {
return nil
}

current := types.CopyWorkObject(head)
var headersWithoutState []*types.WorkObject
for {
headersWithoutState = append(headersWithoutState, current)
header := hc.GetHeaderByHash(current.ParentHash(nodeCtx))
if header == nil {
return ErrSubNotSyncedToDom
}
if hc.IsGenesisHash(header.Hash()) {
break
}

// Check if the state has been processed for this block
processedState := rawdb.ReadProcessedState(hc.headerDb, header.Hash())
if processedState {
break
}
current = types.CopyWorkObject(header)
}

// Run through the hash stack to update canonicalHash and forward state processor
for i := len(headersWithoutState) - 1; i >= 0; i-- {
block := hc.GetBlockOrCandidate(headersWithoutState[i].Hash(), headersWithoutState[i].NumberU64(nodeCtx))
if block == nil {
return errors.New("could not find block during SetCurrentState: " + headersWithoutState[i].Hash().String())
}
err := hc.AppendBlock(block)
if err != nil {
return err
}
}
return nil
}

// findCommonAncestor
func (hc *HeaderChain) findCommonAncestor(header *types.WorkObject) *types.WorkObject {
current := types.CopyWorkObject(header)
Expand All @@ -501,6 +474,57 @@ func (hc *HeaderChain) findCommonAncestor(header *types.WorkObject) *types.WorkO
}

}
func (hc *HeaderChain) WorkShareDistance(wo *types.WorkObject, ws *types.WorkObjectHeader) (*big.Int, error) {
current := wo
// Create a list of ancestor blocks to the work object
ancestors := []*types.WorkObject{}
for i := 0; i < params.WorkSharesInclusionDepth; i++ {
parent := hc.GetBlockByHash(current.ParentHash(common.ZONE_CTX))
if parent == nil {
return big.NewInt(0), errors.New("error finding the parent")
}
ancestors = append(ancestors, parent)
current = parent
}

// checks if the wo is in the ancestors list
checkInAncestorsList := func(wo *types.WorkObject) bool {
for _, wObject := range ancestors {
if wo.Hash() == wObject.Hash() {
return true
}
}
return false
}

var distance int64 = 0
// trace back from the workshare and check if any of the parents exist in
// the ancestors list
parentHash := ws.ParentHash()
for {
parent := hc.GetBlockByHash(parentHash)
if parent == nil {
return big.NewInt(0), errors.New("error finding the parent")
}
if checkInAncestorsList(parent) {
distance += int64(wo.NumberU64(common.ZONE_CTX) - parent.NumberU64(common.ZONE_CTX) - 1)
break
}
distance++
// If distance is greater than the WorkSharesInclusionDepth, exit the for loop
if distance > int64(params.WorkSharesInclusionDepth) {
break
}
parentHash = parent.ParentHash(common.ZONE_CTX)
}

// If distance is greater than the WorkSharesInclusionDepth, reject the workshare
if distance > int64(params.WorkSharesInclusionDepth) {
return big.NewInt(0), errors.New("workshare is at distance more than WorkSharesInclusionDepth")
}

return big.NewInt(distance), nil
}

func (hc *HeaderChain) AddPendingEtxs(pEtxs types.PendingEtxs) error {
if !pEtxs.IsValid(trie.NewStackTrie(nil)) && !hc.IsGenesisHash(pEtxs.Header.Hash()) {
Expand Down
47 changes: 36 additions & 11 deletions core/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,15 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb

setHead = sl.poem(sl.engine.TotalLogS(sl.hc, block), sl.engine.TotalLogS(sl.hc, sl.hc.CurrentHeader()))

err = sl.hc.SetCurrentState(block)
if err != nil {
sl.logger.WithFields(log.Fields{
"err": err,
"Hash": block.Hash(),
}).Error("Error setting current state")
return nil, false, err
if setHead {
err := sl.hc.SetCurrentHeader(block)
if err != nil {
sl.logger.WithFields(log.Fields{
"err": err,
"Hash": block.Hash(),
}).Error("Error setting current header")
return nil, false, err
}
}

// Upate the local pending header
Expand Down Expand Up @@ -400,7 +402,8 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb

time12 := common.PrettyDuration(time.Since(start))

if setHead {
// SetCurrentHeader for prime and region is already called above
if setHead && nodeCtx != common.ZONE_CTX {
sl.hc.SetCurrentHeader(block)
} else if !setHead && nodeCtx == common.ZONE_CTX && sl.hc.ProcessingState() {
sl.logger.WithFields(log.Fields{
Expand Down Expand Up @@ -1115,11 +1118,29 @@ func (sl *Slice) updatePhCacheFromDom(pendingHeader types.PendingHeader, termini
}).Info("Choosing phHeader pickPhHead")
parent := sl.hc.GetBlockByHash(localPendingHeader.WorkObject().ParentHash(nodeCtx))
if parent != nil {
sl.hc.SetCurrentHeader(parent)
err := sl.hc.SetCurrentHeader(parent)
if err != nil {
sl.logger.WithField("err", err).Error("cannot set the current header in sub relay pending header")
return nil
}
newPendingHeader, err := sl.generateSlicePendingHeader(parent, localPendingHeader.Termini(), combinedPendingHeader, true, true, false)
if err != nil {
sl.logger.WithField("err", err).Error("Error generating slice pending header")
return err
}
combinedPendingHeader = types.CopyWorkObject(newPendingHeader.WorkObject())
sl.logger.WithFields(log.Fields{
"NumberArray": combinedPendingHeader.Header().NumberArray(),
"ParentHash": combinedPendingHeader.ParentHash(nodeCtx),
"Terminus": localPendingHeader.Termini().DomTerminus(nodeLocation),
}).Info("Choosing phHeader pickPhHead")
} else {
sl.logger.WithFields(log.Fields{
"hash": localPendingHeader.WorkObject().ParentHash(nodeCtx),
}).Warn("Parent not found")
// This should not be possible, we cannot update the ph cache if
// parent cannot be found
return nil
}
sl.WriteBestPhKey(localPendingHeader.Termini().DomTerminus(nodeLocation))
}
Expand Down Expand Up @@ -1159,7 +1180,7 @@ func (sl *Slice) updatePhCache(pendingHeaderWithTermini types.PendingHeader, inS
if !exists {
return
}
if !sl.poem(bestPh.WorkObject().ParentEntropy(common.ZONE_CTX), pendingHeaderWithTermini.WorkObject().ParentEntropy(common.ZONE_CTX)) {
if !sl.poem(pendingHeaderWithTermini.WorkObject().ParentEntropy(common.ZONE_CTX), bestPh.WorkObject().ParentEntropy(common.ZONE_CTX)) {
return
}
}
Expand Down Expand Up @@ -1257,7 +1278,11 @@ func (sl *Slice) init() error {
return err
}
// This is just done for the startup process
sl.hc.SetCurrentHeader(genesisHeader)
err = sl.hc.SetCurrentHeader(genesisHeader)
if err != nil {
sl.logger.WithField("err", err).Error("Error setting the current header in slice init")
return err
}

if sl.NodeLocation().Context() == common.PRIME_CTX {
go sl.NewGenesisPendingHeader(nil, genesisHash, genesisHash)
Expand Down
4 changes: 4 additions & 0 deletions core/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,10 @@ func (w *worker) commitUncle(env *environment, uncle *types.WorkObjectHeader) er
if err != nil {
workShare = true
}
_, err = w.hc.WorkShareDistance(env.wo, uncle)
if err != nil {
return err
}
if !workShare && (env.wo.ParentHash(w.hc.NodeCtx()) == uncle.ParentHash()) {
return errors.New("uncle is sibling")
}
Expand Down
Loading
Loading