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

Commit

Permalink
feat(protocol): add minTier to BlockProposed event
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaikocha committed Sep 29, 2023
1 parent c0720a5 commit 739affa
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 145 deletions.
28 changes: 28 additions & 0 deletions pkg/rpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,3 +560,31 @@ func (c *Client) IsJustSyncedByP2P(ctx context.Context) (bool, error) {

return false, nil
}

// TierProviderTierWithID wraps protocol ITierProviderTier struct with an ID.
type TierProviderTierWithID struct {
ID uint16
bindings.ITierProviderTier
}

// GetTiers fetches all protocol supported tiers.
func (c *Client) GetTiers(ctx context.Context) ([]*TierProviderTierWithID, error) {
ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout)
defer cancel()

ids, err := c.TaikoL1.GetTierIds(&bind.CallOpts{Context: ctxWithTimeout})
if err != nil {
return nil, err
}

var tiers []*TierProviderTierWithID
for _, id := range ids {
tier, err := c.TaikoL1.GetTier(&bind.CallOpts{Context: ctxWithTimeout}, id)
if err != nil {
return nil, err
}
tiers = append(tiers, &TierProviderTierWithID{ID: id, ITierProviderTier: tier})
}

return tiers, nil
}
25 changes: 7 additions & 18 deletions prover/proof_submitter/valid_proof_submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func (s *ValidProofSubmitter) SubmitProof(
log.Info(
"New valid block proof",
"blockID", proofWithHeader.BlockID,
"proposer", proofWithHeader.Meta.Proposer,
"proposer", proofWithHeader.Meta.Coinbase,
"hash", proofWithHeader.Header.Hash(),
"proof", common.Bytes2Hex(proofWithHeader.ZkProof),
"graffiti", common.Bytes2Hex(s.graffiti[:]),
Expand Down Expand Up @@ -221,34 +221,23 @@ func (s *ValidProofSubmitter) SubmitProof(
return fmt.Errorf("failed to fetch anchor transaction receipt: %w", err)
}

evidence := &encoding.TaikoL1Evidence{
evidence := &encoding.BlockEvidence{
MetaHash: proofWithHeader.Opts.MetaHash,
ParentHash: proofWithHeader.Opts.ParentHash,
BlockHash: proofWithHeader.Opts.BlockHash,
SignalRoot: proofWithHeader.Opts.SignalRoot,
Graffiti: s.graffiti,
Tier: 0, // TODO: update tier
Proofs: zkProof,
}

var circuitsIdx uint16
var prover common.Address

if s.isOracleProver {
prover = encoding.OracleProverAddress

circuitsIdx = uint16(0)
} else {
prover = s.proverAddress

circuitsIdx, err = proofProducer.DegreeToCircuitsIdx(proofWithHeader.Degree)
if err != nil {
return err
}
circuitsIdx, err := proofProducer.DegreeToCircuitsIdx(proofWithHeader.Degree)
if err != nil {
return err
}
evidence.Proofs = append(uint16ToBytes(circuitsIdx), evidence.Proofs...)
evidence.Prover = prover

input, err := encoding.EncodeProveBlockInput(evidence)
input, err := encoding.EncodeEvidence(evidence)
if err != nil {
return fmt.Errorf("failed to encode TaikoL1.proveBlock inputs: %w", err)
}
Expand Down
165 changes: 38 additions & 127 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import (
)

var (
errNoCapacity = errors.New("no prover capacity available")
errNoCapacity = errors.New("no prover capacity available")
errEmptyTiersList = errors.New("empty proof tiers list in protocol")
)

type cancelFunc func()
Expand All @@ -58,18 +59,19 @@ type Prover struct {
genesisHeightL1 uint64
l1Current *types.Header
reorgDetectedFlag bool
tiers []*rpc.TierProviderTierWithID

// Proof submitters
validProofSubmitter proofSubmitter.ProofSubmitter

// Subscriptions
blockProposedCh chan *bindings.TaikoL1ClientBlockProposed
blockProposedSub event.Subscription
transitionProvenCh chan *bindings.TaikoL1ClientTransitionProved
blockProvenSub event.Subscription
blockVerifiedCh chan *bindings.TaikoL1ClientBlockVerified
blockVerifiedSub event.Subscription
proveNotify chan struct{}
blockProposedCh chan *bindings.TaikoL1ClientBlockProposed
blockProposedSub event.Subscription
transitionProvedCh chan *bindings.TaikoL1ClientTransitionProved
transitionProvedSub event.Subscription
blockVerifiedCh chan *bindings.TaikoL1ClientBlockVerified
blockVerifiedSub event.Subscription
proveNotify chan struct{}

// Proof related
proofGenerationCh chan *proofProducer.ProofWithHeader
Expand Down Expand Up @@ -143,7 +145,7 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
chBufferSize := p.protocolConfigs.BlockMaxProposals
p.blockProposedCh = make(chan *bindings.TaikoL1ClientBlockProposed, chBufferSize)
p.blockVerifiedCh = make(chan *bindings.TaikoL1ClientBlockVerified, chBufferSize)
p.transitionProvenCh = make(chan *bindings.TaikoL1ClientTransitionProved, chBufferSize)
p.transitionProvedCh = make(chan *bindings.TaikoL1ClientTransitionProved, chBufferSize)
p.proofGenerationCh = make(chan *proofProducer.ProofWithHeader, chBufferSize)
p.proveNotify = make(chan struct{}, 1)
if err := p.initL1Current(cfg.StartingBlockID); err != nil {
Expand Down Expand Up @@ -204,6 +206,13 @@ func InitFromConfig(ctx context.Context, p *Prover, cfg *Config) (err error) {
return err
}

if p.tiers, err = p.rpc.GetTiers(ctx); err != nil {
return err
}
if len(p.tiers) == 0 {
return errEmptyTiersList
}

// Prover server
proverServerOpts := &server.NewProverServerOpts{
ProverPrivateKey: p.cfg.L1ProverPrivKey,
Expand Down Expand Up @@ -304,7 +313,7 @@ func (p *Prover) eventLoop() {
if err := p.onBlockVerified(p.ctx, e); err != nil {
log.Error("Handle BlockVerified event error", "error", err)
}
case e := <-p.transitionProvenCh:
case e := <-p.transitionProvedCh:
if err := p.onBlockProven(p.ctx, e); err != nil {
log.Error("Handle BlockProven event error", "error", err)
}
Expand Down Expand Up @@ -485,7 +494,7 @@ func (p *Prover) onBlockProposed(
log.Info(
"Proposed block information",
"blockID", event.BlockId,
"prover", block.Prover,
"assignedProver", block.AssignedProver,
"proposedAt", block.ProposedAt,
)

Expand Down Expand Up @@ -543,15 +552,13 @@ func (p *Prover) onBlockProposed(
proofWindowExpiresAt := block.ProposedAt + uint64(p.protocolConfigs.ProofWindow)
proofWindowExpired := uint64(time.Now().Unix()) > proofWindowExpiresAt
// zero address means anyone can prove, proofWindowExpired means anyone can prove even if not zero address
if block.Prover != p.proverAddress &&
!proofWindowExpired &&
!(block.Prover == encoding.OracleProverAddress && p.oracleProverAddress == p.proverAddress) {
if block.AssignedProver != p.proverAddress && !proofWindowExpired {
log.Info(
"Proposed block not provable",
"blockID",
event.BlockId,
"prover",
block.Prover.Hex(),
"assignedProver",
block.AssignedProver.Hex(),
"proofWindowExpiresAt",
proofWindowExpiresAt,
"timeToExpire",
Expand All @@ -564,8 +571,8 @@ func (p *Prover) onBlockProposed(
log.Info("Adding proposed block to wait for proof window expiration",
"blockID",
event.BlockId,
"prover",
block.Prover.Hex(),
"assignedProver",
block.AssignedProver.Hex(),
"proofWindowExpiresAt",
proofWindowExpiresAt,
)
Expand All @@ -591,7 +598,7 @@ func (p *Prover) onBlockProposed(
log.Info(
"Proposed block is provable",
"blockID", event.BlockId,
"prover", block.Prover.Hex(),
"assignedProver", block.AssignedProver.Hex(),
"proofWindowExpired", proofWindowExpired,
)

Expand Down Expand Up @@ -699,13 +706,8 @@ func (p *Prover) onBlockVerified(ctx context.Context, event *bindings.TaikoL1Cli

// onBlockProven cancels proof generation if the proof is being generated by this prover,
// and the proof is not the oracle proof address.
func (p *Prover) onBlockProven(ctx context.Context, event *bindings.TaikoL1ClientBlockProven) error {
func (p *Prover) onBlockProven(ctx context.Context, event *bindings.TaikoL1ClientTransitionProved) error {
metrics.ProverReceivedProvenBlockGauge.Update(event.BlockId.Int64())
// if this proof is submitted by an oracle prover or a system prover, don't cancel proof.
if event.Prover == p.oracleProverAddress ||
event.Prover == encoding.OracleProverAddress {
return nil
}

// cancel any proofs being generated for this block
isValidProof, err := p.isValidProof(
Expand Down Expand Up @@ -799,7 +801,7 @@ func (p *Prover) isBlockVerified(id *big.Int) (bool, error) {
func (p *Prover) initSubscription() {
p.blockProposedSub = rpc.SubscribeBlockProposed(p.rpc.TaikoL1, p.blockProposedCh)
p.blockVerifiedSub = rpc.SubscribeBlockVerified(p.rpc.TaikoL1, p.blockVerifiedCh)
p.blockProvenSub = rpc.SubscribeBlockProven(p.rpc.TaikoL1, p.transitionProvenCh)
p.transitionProvedSub = rpc.SubscribeTransitionProved(p.rpc.TaikoL1, p.transitionProvedCh)
}

// closeSubscription closes all subscriptions.
Expand Down Expand Up @@ -882,107 +884,6 @@ func (p *Prover) cancelProof(ctx context.Context, blockID uint64) {
}
}

// checkProofWindowsExpired iterates through the current blocks waiting for proof window to expire,
// which are blocks that have been proposed, but we were not selected as the prover. if the proof window
// has expired, we can start generating a proof for them.
func (p *Prover) checkProofWindowsExpired(ctx context.Context) error {
p.currentBlocksWaitingForProofWindowMutex.Lock()
defer p.currentBlocksWaitingForProofWindowMutex.Unlock()

for blockId, l1Height := range p.currentBlocksWaitingForProofWindow {
if err := p.checkProofWindowExpired(ctx, l1Height, blockId); err != nil {
return err
}
}

return nil
}

// checkProofWindowExpired checks a single instance of a block to see if its proof window has expired
// and the proof is now able to be submitted by anyone, not just the blocks assigned prover.
func (p *Prover) checkProofWindowExpired(ctx context.Context, l1Height, blockId uint64) error {
block, err := p.rpc.TaikoL1.GetBlock(&bind.CallOpts{Context: ctx}, blockId)
if err != nil {
return encoding.TryParsingCustomError(err)
}

isExpired := time.Now().Unix() > int64(block.ProposedAt)+int64(p.protocolConfigs.ProofWindow)

if isExpired {
log.Debug(
"Block proof window is expired",
"blockID", blockId,
"l1Height", l1Height,
)

// we should remove this block from being watched regardless of whether the block
// has a valid proof
delete(p.currentBlocksWaitingForProofWindow, blockId)

// we can see if a fork choice with correct parentHash/gasUsed has come in.
// if it hasnt, we can start to generate a proof for this.
parent, err := p.rpc.L2ParentByBlockId(ctx, new(big.Int).SetUint64(blockId))
if err != nil {
return err
}

transition, err := p.rpc.TaikoL1.GetTransition(
&bind.CallOpts{Context: ctx},
blockId,
parent.Hash(),
)

if err != nil && !strings.Contains(encoding.TryParsingCustomError(err).Error(), "L1_TRANSITION_NOT_FOUND") {
return encoding.TryParsingCustomError(err)
}

if transition.Prover == rpc.ZeroAddress {
log.Info(
"Proof window for proof not assigned to us expired, requesting proof",
"blockID", blockId,
"l1Height", l1Height,
)
// we can generate the proof, no proof came in by proof window expiring
if err := p.requestProofForBlockId(
new(big.Int).SetUint64(blockId),
new(big.Int).SetUint64(l1Height),
); err != nil {
return err
}
} else {
// we need to check the block hash vs the proof's blockHash to see
// if the proof is valid or not
block, err := p.rpc.L2.BlockByNumber(ctx, new(big.Int).SetUint64(blockId))
if err != nil {
return err
}

// if the hashes dont match, we can generate proof even though
// a proof came in before proofwindow expired.
if block.Hash() != transition.BlockHash {
log.Info(
"Invalid proof detected while watching for proof window expiration, requesting proof",
"blockID", blockId,
"l1Height", l1Height,
"expectedBlockHash", block.Hash(),
"transitionBlockHash", common.Bytes2Hex(transition.BlockHash[:]),
)
// we can generate the proof, the proof is incorrect since blockHash does not match
// the correct one but parentHash/gasUsed are correct.
if err := p.requestProofForBlockId(
new(big.Int).SetUint64(blockId),
new(big.Int).SetUint64(l1Height),
); err != nil {
return err
}
}
}
}

// otherwise, keep it in the map and check again next iteration
return nil
}

// proveOp performs a proving operation, find current unproven blocks, then
// request generating proofs for them.
func (p *Prover) requestProofForBlockId(blockId *big.Int, l1Height *big.Int) error {
Expand Down Expand Up @@ -1067,3 +968,13 @@ func (p *Prover) requestProofForBlockId(blockId *big.Int, l1Height *big.Int) err

return nil
}

func proofWindow(tiers []*rpc.TierProviderTierWithID, id uint64) (uint64, error) {
for _, tier := range tiers {
if tier.ID == id {

}
}

return 0, fmt.Errorf("tier id not found: %d", id)
}

0 comments on commit 739affa

Please sign in to comment.