-
Notifications
You must be signed in to change notification settings - Fork 260
feat: Generate fraud proof after trigger #498
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
Changes from all commits
656d4ee
d749e4c
3e7c1d9
af2e8cd
cf43b3b
08ae559
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| syntax = "proto3"; | ||
| package tendermint.version; | ||
|
|
||
| option go_package = "github.com/tendermint/tendermint/proto/tendermint/version"; | ||
|
|
||
| import "gogoproto/gogo.proto"; | ||
|
|
||
| // App includes the protocol and software version for the application. | ||
| // This information is included in ResponseInfo. The App.Protocol can be | ||
| // updated in ResponseEndBlock. | ||
| message App { | ||
| uint64 protocol = 1; | ||
| string software = 2; | ||
| } | ||
|
|
||
| // Consensus captures the consensus rules for processing a block in the blockchain, | ||
| // including all blockchain data structures and the rules of the application's | ||
| // state transition machine. | ||
| message Consensus { | ||
| option (gogoproto.equal) = true; | ||
|
|
||
| uint64 block = 1; | ||
| uint64 app = 2; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ import ( | |
| "github.com/celestiaorg/optimint/types" | ||
| ) | ||
|
|
||
| var fraudProofsEnabled = true | ||
|
|
||
| // BlockExecutor creates and applies blocks and maintains state. | ||
| type BlockExecutor struct { | ||
| proposerAddress []byte | ||
|
|
@@ -268,18 +270,18 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t | |
| currentIsrs := block.Data.IntermediateStateRoots.RawRootsList | ||
| currentIsrIndex := 0 | ||
|
|
||
| if currentIsrs != nil { | ||
| expectedLength := len(block.Data.Txs) + 2 | ||
| // BeginBlock + DeliverTxs + EndBlock | ||
| if len(currentIsrs) != expectedLength { | ||
| return nil, fmt.Errorf("invalid length of ISR list: %d, expected length: %d", len(currentIsrs), expectedLength) | ||
| if fraudProofsEnabled { | ||
| if currentIsrs != nil { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add an else here and halt there |
||
| expectedLength := len(block.Data.Txs) + 2 | ||
| // BeginBlock + DeliverTxs + EndBlock | ||
| if len(currentIsrs) != expectedLength { | ||
| return nil, fmt.Errorf("invalid length of ISR list: %d, expected length: %d", len(currentIsrs), expectedLength) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| ISRs := make([][]byte, 0) | ||
|
|
||
| var err error | ||
|
|
||
| e.proxyApp.SetResponseCallback(func(req *abci.Request, res *abci.Response) { | ||
| if r, ok := res.Value.(*abci.Response_DeliverTx); ok { | ||
| txRes := r.DeliverTx | ||
|
|
@@ -301,80 +303,130 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t | |
| } | ||
| abciHeader.ChainID = e.chainID | ||
| abciHeader.ValidatorsHash = state.Validators.Hash() | ||
| abciResponses.BeginBlock, err = e.proxyApp.BeginBlockSync( | ||
| abci.RequestBeginBlock{ | ||
| Hash: hash[:], | ||
| Header: abciHeader, | ||
| LastCommitInfo: abci.LastCommitInfo{ | ||
| Round: 0, | ||
| Votes: nil, | ||
| }, | ||
| ByzantineValidators: nil, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| isr, err := e.getAppHash() | ||
| if err != nil { | ||
| return nil, err | ||
| beginBlockRequest := abci.RequestBeginBlock{ | ||
| Hash: hash[:], | ||
| Header: abciHeader, | ||
| LastCommitInfo: abci.LastCommitInfo{ | ||
| Round: 0, | ||
| Votes: nil, | ||
| }, | ||
| ByzantineValidators: nil, | ||
| } | ||
| ISRs = append(ISRs, isr) | ||
| err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| abciResponses.BeginBlock, err = e.proxyApp.BeginBlockSync(beginBlockRequest) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| currentIsrIndex++ | ||
|
|
||
| for _, tx := range block.Data.Txs { | ||
| res := e.proxyApp.DeliverTxAsync(abci.RequestDeliverTx{Tx: tx}) | ||
| if res.GetException() != nil { | ||
| return nil, errors.New(res.GetException().GetError()) | ||
| } | ||
| if fraudProofsEnabled { | ||
| isr, err := e.getAppHash() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| ISRs = append(ISRs, isr) | ||
| err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| if err != nil { | ||
| return nil, err | ||
| isFraud := e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| if isFraud { | ||
| fraudProof, err := e.generateFraudProof(&beginBlockRequest, nil, nil) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // TODO: gossip fraudProof to P2P network | ||
| // fraudTx: BeginBlock | ||
| _ = fraudProof | ||
| } | ||
| currentIsrIndex++ | ||
| } | ||
| deliverTxRequests := make([]*abci.RequestDeliverTx, len(block.Data.Txs)) | ||
| for _, tx := range block.Data.Txs { | ||
| deliverTxRequest := abci.RequestDeliverTx{Tx: tx} | ||
| deliverTxRequests = append(deliverTxRequests, &deliverTxRequest) | ||
| res := e.proxyApp.DeliverTxAsync(deliverTxRequest) | ||
| if res.GetException() != nil { | ||
| return nil, errors.New(res.GetException().GetError()) | ||
| } | ||
|
|
||
| abciResponses.EndBlock, err = e.proxyApp.EndBlockSync(abci.RequestEndBlock{Height: int64(block.Header.Height)}) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| isr, err = e.getAppHash() | ||
| if err != nil { | ||
| return nil, err | ||
| if fraudProofsEnabled { | ||
| isr, err := e.getAppHash() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| ISRs = append(ISRs, isr) | ||
| isFraud := e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| if isFraud { | ||
| fraudProof, err := e.generateFraudProof(&beginBlockRequest, deliverTxRequests, nil) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // TODO: gossip fraudProof to P2P network | ||
| // fraudTx: current DeliverTx | ||
| _ = fraudProof | ||
| } | ||
| currentIsrIndex++ | ||
| } | ||
| } | ||
| ISRs = append(ISRs, isr) | ||
| err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| endBlockRequest := abci.RequestEndBlock{Height: int64(block.Header.Height)} | ||
| abciResponses.EndBlock, err = e.proxyApp.EndBlockSync(endBlockRequest) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if block.Data.IntermediateStateRoots.RawRootsList == nil { | ||
| // Block producer: Initial ISRs generated here | ||
| block.Data.IntermediateStateRoots.RawRootsList = ISRs | ||
|
|
||
| if fraudProofsEnabled { | ||
| isr, err := e.getAppHash() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| ISRs = append(ISRs, isr) | ||
| isFraud := e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) | ||
| if isFraud { | ||
| fraudProof, err := e.generateFraudProof(&beginBlockRequest, deliverTxRequests, &endBlockRequest) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // TODO: gossip fraudProof to P2P network | ||
| // fraudTx: EndBlock | ||
| _ = fraudProof | ||
| } | ||
| if block.Data.IntermediateStateRoots.RawRootsList == nil { | ||
| // Block producer: Initial ISRs generated here | ||
| block.Data.IntermediateStateRoots.RawRootsList = ISRs | ||
| } | ||
| } | ||
|
|
||
| return abciResponses, nil | ||
| } | ||
|
|
||
| func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) error { | ||
| func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) bool { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of passing |
||
| if currentIsrs != nil { | ||
| stateIsr := currentIsrs[index] | ||
| if !bytes.Equal(stateIsr, generatedIsr) { | ||
| e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) | ||
| _, err := e.proxyApp.TriggerFraudProofGenerationModeSync(abci.RequestTriggerFraudProofGenerationMode{}) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| return true | ||
| } | ||
| } | ||
| return nil | ||
| return false | ||
| } | ||
|
|
||
| func (e *BlockExecutor) generateFraudProof(beginBlockRequest *abci.RequestBeginBlock, deliverTxRequests []*abci.RequestDeliverTx, endBlockRequest *abci.RequestEndBlock) (*abci.FraudProof, error) { | ||
| generateFraudProofRequest := abci.RequestGenerateFraudProof{} | ||
| if beginBlockRequest == nil { | ||
| return nil, fmt.Errorf("begin block request cannot be a nil parameter") | ||
| } | ||
| generateFraudProofRequest.BeginBlockRequest = *beginBlockRequest | ||
| if deliverTxRequests != nil { | ||
| generateFraudProofRequest.DeliverTxRequests = deliverTxRequests | ||
| if endBlockRequest != nil { | ||
| generateFraudProofRequest.EndBlockRequest = endBlockRequest | ||
| } | ||
| } | ||
| resp, err := e.proxyApp.GenerateFraudProofSync(generateFraudProofRequest) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if resp.FraudProof != nil { | ||
| return resp.FraudProof, nil | ||
|
|
||
| } else { | ||
| return nil, fmt.Errorf("fraud proof generation failed") | ||
| } | ||
| } | ||
|
|
||
| func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be global. Please move it to
BlockExecutorstruct.