Skip to content

fatal-fruit/abci-workshop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ABCI++ Workshop

Joint workshop between Cosmos SDK and CometBFT for Hackmos at Cosmoverse.

Supported by Informal Systems and Binary Builders.

Concepts

Overview

The goal of this workshop is to demonstrate to developers how they might think about utilizing ABCI++ and new features in the Eden release of the Cosmos SDK.

In part 1, we explore the application and discuss a potential vector for MEV by leveraging custom block building in PreparePropsoal for a chain running perpetual nameservice auctions.

In part 2 and 3, we build a solution to mitigate auction front running by extending functionality in ExtendVote, PrepareProposal, and ProcessProposal. This solution assumes an honest 2/3 majority of validators are not colluding to front run transactions.

At H-1 during ExtendVote, we check the mempool for unconfirmed transactions and select all auction bids. Validators submit their Vote Extension with a list of all bids available in their mempool. Additionally we implement a custom app side ThresholdMempool, which guarantees that transactions can only be included in a proposal if they have been seen by ExtendVote at H-1.

At H during PrepareProposal, the validator will process all bids included in Vote Extensions from H-1. It will inject this result into a Special Transaction to be included in the proposal. During the subsequent ProcessProposal, validators will check if there are any bid transactions. Bids included in the proposal will be validated against the bids included in the Special Transaction. If a bid included in the proposal does not meet the minimum threshold of inclusion frequency in Vote Extensions from H-1, the proposal is rejected.

Content

  • Getting Started
  • Exploring MEV Mitigation
  1. Submit Proof of Existence with Vote Extensions
  2. Winning the Race: Modifying the Mempool
  1. Collating Evidence in Prepare Proposal
  2. Detecting & Deflecting Misbehavior with Process Proposal

Intro

Content

  • ABCI++ Overview
  • Tour of App
  • Understanding the Problem

ABCI++ Overview

Tour of the App

  • How to configure:
    • App side mempool
    • Vote Extensions
      • Consensus Params
      • App Opts
    • Prepare Proposal Handler
    • Process Proposal Handler

Understanding the Problem

  • Diagram Overview
  • Demos
    • Part 1
    • Final Solution
  • Code Walkthrough

Part 1

In the first part we'll configure vote extensions to peek into the mempool and submit a list of all unconfirmed bids.

Then we'll verify that we can access the list of unconfirmed transactions in the abci.RequestPrepareProposal during the following block. Vote Extensions can be found in LocalLastCommit.

1. Create Vote Extension Handler In /abci/proposal.go

func (h *VoteExtHandler) ExtendVoteHandler() sdk.ExtendVoteHandler {
	return func(ctx sdk.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {

      // Get unconfirmed transactions from mempool

      // Iterate through reaped transactions, msgs and check for bids

      // Move tx to ready pool
		
      // Create vote extension
      
      // Marshal Vote Extension
		
	 // Return RequestExtendVote
    }
}

2. Configure Handler in App In /app/app.go

bApp := baseapp.NewBaseApp(AppName, logger, db, txConfig.TxDecoder(), baseAppOptions...)

...
// 
voteExtHandler := abci2.NewVoteExtensionHandler(logger, mempool, appCodec)
bApp.SetExtendVoteHandler(voteExtHandler.ExtendVoteHandler())

3. Validate Vote Extensions propagagted We want to add the following to the PrepareProposalHandler to print out and test our vote extensions have entere

if req.Height > 2 {  
   voteExt := req.GetLocalLastCommit()  
   h.logger.Info(fmt.Sprintf("🛠️ :: Get vote extensions: %v", voteExt))  
}

Part 2

In the second part, in Prepare Proposal we'll process the vote extensions from the previous round and inject them into the proposal via a special transaction.

In Process Proposal, if a proposal contains a bid, we examine the bids in the special transaction and verify that this bid has been included in the previous height's vote extensions.

1. Process Vote Extensions in Prepare Proposal

func (h *PrepareProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
	return func(ctx sdk.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {

      // Get VE from ProposedLastCommit

      // Get Special Transaction

      // Append Special Transaction to proposal
}

2. Create Process Proposal Handler

func (h *ProcessProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
	return func(ctx sdk.Context, req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) {

        // The first transaction will always be the Special Transaction
        
        // But we want to first check if the proposal has any transactions

        // Double check if the first transaction is the special transaction and if it is we always want to Unmarshal

        // Check if there are any bids in the Special Transaction

        // Unmarshal the bids

        // Validate these bids
    }
}

3. Configure Process Proposal Handler in App In /app/app.go

processPropHandler := abci2.ProcessProposalHandler{app.txConfig, appCodec, logger}
bApp.SetProcessProposal(processPropHandler.ProcessProposalHandler())

If you want to validate the bids such as we have in this example you must ensure you do the following:

  • Decode the proposal transactions and extract the bids
  • Map bid frequencies, where the number of times the bid appears in the VE is stored
  • Figure out how many votes are needed for a bid to be considered valid
  • Iterate over the bids in the proposal and check if each bid appears in the VE at least as many times as the threshold count (for the threshold count we will need to implement the ThresholdMempool)

3 Validator Network

In the 3 validator network, the Beacon validator has a custom transaction provider enabled. It might take a few tries before the transaction is picked up and front ran by the Beacon.

After submitting the following transaction, we should be able to see the proposal accepted or rejected in the logs. Note that it is best to submit the transaction after the Beacon has just proposed a successful proposal.

./scripts/reserve.sh "bob.cosmos"

Query to verify the name has been reserved

./scripts/whois.sh "bob.cosmos"

If the Beacon attempts to front run the bid, we will see the following logs during ProcessProposal

2:47PM ERR ❌️:: Detected invalid proposal bid :: name:"bob.cosmos" resolveAddress:"cosmos1wmuwv38pdur63zw04t0c78r2a8dyt08hf9tpvd" owner:"cosmos1wmuwv38pdur63zw04t0c78r2a8dyt08hf9tpvd" amount:<denom:"uatom" amount:"2000" >  module=server
2:47PM ERR ❌️:: Unable to validate bids in Process Proposal :: <nil> module=server
2:47PM ERR prevote step: state machine rejected a proposed block; this should not happen:the proposer may be misbehaving; prevoting nil err=null height=142 module=consensus round=0

Single Node

./build/cosmappd tx ns reserve "bob.cosmos" $(./build/cosmappd keys show alice -a --keyring-backend test) 1000uatom --from $(./build/cosmappd keys show bob -a --keyring-backend test) -y

Query to verify the name has been reserved.

If running the provider on the part-1-2 branch, we can see that the owner and resolve address are different than the original transaction we submitted.

./build/cosmappd q ns whois "bob.cosmos" -o json

./build/cosmappd keys list --keyring-backend test --output json | jq

Resources

Official Docs

ABCI++

Building Applications