From 267c1d566b5be703a6da07687098f8ba50872459 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Tue, 23 Aug 2022 23:50:52 -0400 Subject: [PATCH 01/10] Add types.proto for new tendermint version with abci methods --- proto/tendermint/abci/types.proto | 88 ++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 8e3a909363..0e02d0ad44 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -36,6 +36,9 @@ message Request { RequestOfferSnapshot offer_snapshot = 13; RequestLoadSnapshotChunk load_snapshot_chunk = 14; RequestApplySnapshotChunk apply_snapshot_chunk = 15; + RequestGetAppHash get_app_hash = 16; + RequestGenerateFraudProof generate_fraud_proof = 17; + RequestTriggerFraudProofGenerationMode trigger_fraud_proof_generation_mode = 18; } } @@ -102,8 +105,7 @@ message RequestEndBlock { message RequestCommit {} // lists available snapshots -message RequestListSnapshots { -} +message RequestListSnapshots {} // offers a snapshot to the application message RequestOfferSnapshot { @@ -125,6 +127,15 @@ message RequestApplySnapshotChunk { string sender = 3; } +// Gets the current appHash +message RequestGetAppHash {} + +// Generates a fraud proof +message RequestGenerateFraudProof {} + +// Triggers fraud proof generation mode +message RequestTriggerFraudProofGenerationMode {} + //---------------------------------------- // Response types @@ -146,6 +157,9 @@ message Response { ResponseOfferSnapshot offer_snapshot = 14; ResponseLoadSnapshotChunk load_snapshot_chunk = 15; ResponseApplySnapshotChunk apply_snapshot_chunk = 16; + ResponseGetAppHash get_app_hash = 17; + ResponseGenerateFraudProof generate_fraud_proof = 18; + ResponseTriggerFraudProofGenerationMode trigger_fraud_proof_generation_mode = 19; } } @@ -212,6 +226,12 @@ message ResponseCheckTx { repeated Event events = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; string codespace = 8; + string sender = 9; + int64 priority = 10; + + // mempool_error is set by Tendermint. + // ABCI applictions creating a ResponseCheckTX should not set mempool_error. + string mempool_error = 11; } message ResponseDeliverTx { @@ -221,16 +241,17 @@ message ResponseDeliverTx { string info = 4; // nondeterministic int64 gas_wanted = 5 [json_name = "gas_wanted"]; int64 gas_used = 6 [json_name = "gas_used"]; - repeated Event events = 7 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic + repeated Event events = 7 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "events,omitempty" + ]; // nondeterministic string codespace = 8; } message ResponseEndBlock { - repeated ValidatorUpdate validator_updates = 1 - [(gogoproto.nullable) = false]; - ConsensusParams consensus_param_updates = 2; - repeated Event events = 3 + repeated ValidatorUpdate validator_updates = 1 [(gogoproto.nullable) = false]; + ConsensusParams consensus_param_updates = 2; + repeated Event events = 3 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; } @@ -276,6 +297,18 @@ message ResponseApplySnapshotChunk { } } +message ResponseGetAppHash { + bytes app_hash = 1; +} + +message ResponseGenerateFraudProof { + FraudProof fraudProof = 1; +} + +message ResponseTriggerFraudProofGenerationMode { + bool success = 1; +} + //---------------------------------------- // Misc. @@ -364,10 +397,8 @@ message Evidence { // The height when the offense occurred int64 height = 3; // The corresponding time where the offense occurred - google.protobuf.Timestamp time = 4 [ - (gogoproto.nullable) = false, - (gogoproto.stdtime) = true - ]; + google.protobuf.Timestamp time = 4 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; // Total voting power of the validator set in case the ABCI application does // not store historical validators. // https://github.com/tendermint/tendermint/issues/4581 @@ -385,6 +416,30 @@ message Snapshot { bytes metadata = 5; // Arbitrary application metadata } +// Represents a single-round fraudProof +message FraudProof { + int64 block_height = 1; + bytes appHash = 2; + map stateWitness = 3; +} + +// State witness with a list of all witness data +message StateWitness { + // store level proof + tendermint.crypto.ProofOp proof_op = 1; + // substore level hash + bytes rootHash = 2; + // List of witness data + repeated WitnessData witnessData = 3; +} + +// Witness data containing a key/value pair and a SMT proof for said key/value pair +message WitnessData { + bytes key = 1; + bytes value = 2; + tendermint.crypto.ProofOp proof = 3; +} + //---------------------------------------- // Service Definition @@ -402,6 +457,11 @@ service ABCIApplication { rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots); rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot); - rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); - rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); + rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) + returns (ResponseLoadSnapshotChunk); + rpc ApplySnapshotChunk(RequestApplySnapshotChunk) + returns (ResponseApplySnapshotChunk); + rpc GetAppHash(RequestGetAppHash) returns (ResponseGetAppHash); + rpc GenerateFraudProof(RequestGenerateFraudProof) returns (ResponseGenerateFraudProof); + rpc TriggerFraudProofGenerationMode(RequestTriggerFraudProofGenerationMode) returns (ResponseTriggerFraudProofGenerationMode); } From 3f1b57360b4d93287670ecd3f3ea6c74400515da Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 00:29:42 -0400 Subject: [PATCH 02/10] Trigger Fraud Proof WIP --- mocks/Application.go | 43 +++++++++++++++ node/integration_test.go | 114 ++++++++++++++++++++++++++++++++++++--- state/executor.go | 56 +++++++++++++++++++ 3 files changed, 205 insertions(+), 8 deletions(-) diff --git a/mocks/Application.go b/mocks/Application.go index 8467676da0..0f0b29049a 100644 --- a/mocks/Application.go +++ b/mocks/Application.go @@ -68,6 +68,49 @@ func (_m *Application) Commit() types.ResponseCommit { return r0 } +// Commit provides a mock function with given fields: +func (_m *Application) GenerateFraudProof(_a0 types.RequestGenerateFraudProof) types.ResponseGenerateFraudProof { + ret := _m.Called(_a0) + + var r0 types.ResponseGenerateFraudProof + if rf, ok := ret.Get(0).(func(types.RequestGenerateFraudProof) types.ResponseGenerateFraudProof); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseGenerateFraudProof) + } + + return r0 +} + +// Commit provides a mock function with given fields: +func (_m *Application) GetAppHash(_a0 types.RequestGetAppHash) types.ResponseGetAppHash { + ret := _m.Called(_a0) + + var r0 types.ResponseGetAppHash + if rf, ok := ret.Get(0).(func(types.RequestGetAppHash) types.ResponseGetAppHash); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseGetAppHash) + } + + return r0 +} + +// Commit provides a mock function with given fields: +func (_m *Application) TriggerFraudProofGenerationMode(_a0 types.RequestTriggerFraudProofGenerationMode) types.ResponseTriggerFraudProofGenerationMode { + ret := _m.Called(_a0) + + var r0 types.ResponseTriggerFraudProofGenerationMode + if rf, ok := ret.Get(0).(func(types.RequestTriggerFraudProofGenerationMode) types.ResponseTriggerFraudProofGenerationMode); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseTriggerFraudProofGenerationMode) + } + + return r0 +} + + // DeliverTx provides a mock function with given fields: _a0 func (_m *Application) DeliverTx(_a0 types.RequestDeliverTx) types.ResponseDeliverTx { ret := _m.Called(_a0) diff --git a/node/integration_test.go b/node/integration_test.go index 568f548dd4..aa2f6c895d 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -89,7 +89,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { var wg sync.WaitGroup clientNodes := 4 - nodes, apps := createNodes(clientNodes+1, &wg, t) + nodes, apps := createNodes(clientNodes+1, false, &wg, t) wg.Add((clientNodes + 1) * clientNodes) for _, n := range nodes { @@ -159,7 +159,85 @@ func TestTxGossipingAndAggregation(t *testing.T) { } } -func createNodes(num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { +func TestFraudProofGenerationTrigger(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + var wg sync.WaitGroup + clientNodes := 4 + + nodes, apps := createNodes(clientNodes+1, true, &wg, t) + + wg.Add((clientNodes + 1) * clientNodes) + for _, n := range nodes { + require.NoError(n.Start()) + } + + time.Sleep(1 * time.Second) + + for i := 1; i < len(nodes); i++ { + data := strconv.Itoa(i) + time.Now().String() + require.NoError(nodes[i].P2P.GossipTx(context.TODO(), []byte(data))) + } + + timeout := time.NewTimer(time.Second * 30) + doneChan := make(chan struct{}) + go func() { + defer close(doneChan) + wg.Wait() + }() + select { + case <-doneChan: + case <-timeout.C: + t.FailNow() + } + + for _, n := range nodes { + require.NoError(n.Stop()) + } + aggApp := apps[0] + apps = apps[1:] + + aggApp.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + aggApp.AssertExpectations(t) + + for i, app := range apps { + app.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + app.AssertNumberOfCalls(t, "GenerateFraudProof", 1) + app.AssertExpectations(t) + + // assert that we have most of the blocks from aggregator + beginCnt := 0 + endCnt := 0 + commitCnt := 0 + for _, call := range app.Calls { + switch call.Method { + case "BeginBlock": + beginCnt++ + case "EndBlock": + endCnt++ + case "Commit": + commitCnt++ + } + } + aggregatorHeight := nodes[0].Store.Height() + adjustedHeight := int(aggregatorHeight - 3) // 3 is completely arbitrary + assert.GreaterOrEqual(beginCnt, adjustedHeight) + assert.GreaterOrEqual(endCnt, adjustedHeight) + assert.GreaterOrEqual(commitCnt, adjustedHeight) + + // assert that all blocks known to node are same as produced by aggregator + for h := uint64(1); h <= nodes[i].Store.Height(); h++ { + nodeBlock, err := nodes[i].Store.LoadBlock(h) + require.NoError(err) + aggBlock, err := nodes[0].Store.LoadBlock(h) + require.NoError(err) + assert.Equal(aggBlock, nodeBlock) + } + } +} + +func createNodes(num int, isAggregatorMalicious bool, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { t.Helper() // create keys first, as they are required for P2P connections @@ -173,15 +251,15 @@ func createNodes(num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.A dalc := &mockda.MockDataAvailabilityLayerClient{} _ = dalc.Init(nil, store.NewDefaultInMemoryKVStore(), log.TestingLogger()) _ = dalc.Start() - nodes[0], apps[0] = createNode(0, true, dalc, keys, wg, t) + nodes[0], apps[0] = createNode(0, isAggregatorMalicious, true, dalc, keys, wg, t) for i := 1; i < num; i++ { - nodes[i], apps[i] = createNode(i, false, dalc, keys, wg, t) + nodes[i], apps[i] = createNode(i, isAggregatorMalicious, false, dalc, keys, wg, t) } return nodes, apps } -func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { +func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { t.Helper() require := require.New(t) // nodes will listen on consecutive ports on local interface @@ -208,13 +286,22 @@ func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, key app := &mocks.Application{} app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{}) app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) - app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) - app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) + app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{Events: generateEventsWithOneEventIsr(t)}) + app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{Events: generateEventsWithOneEventIsr(t)}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) - app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}).Run(func(args mock.Arguments) { + + deliverTxEvents := generateEventsWithOneEventIsr(t) + if isMalicious { + deliverTxEvents[0].Attributes[0].Value = []byte{9, 8, 7, 6} + } + app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{Events: deliverTxEvents}).Run(func(args mock.Arguments) { wg.Done() }) + if isMalicious && !aggregator { + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + } + signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) node, err := NewNode( context.Background(), @@ -238,3 +325,14 @@ func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, key return node, app } + +func generateEventsWithOneEventIsr(t *testing.T) []abci.Event { + t.Helper() + return []abci.Event{{ + Type: "isr", + Attributes: []abci.EventAttribute{{ + Key: []byte("isr"), + Value: []byte{1, 2, 3, 4}, + }}, + }} +} diff --git a/state/executor.go b/state/executor.go index 00075f0f07..6d96f69aea 100644 --- a/state/executor.go +++ b/state/executor.go @@ -265,11 +265,39 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t validTxs := 0 invalidTxs := 0 + 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) + } + } + + 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 + + if currentIsrs != nil { + generatedIsr, err := e.getAppHash() + if err != nil { + return + } + deliverTxIsr := currentIsrs[currentIsrIndex] + currentIsrIndex++ + if !bytes.Equal(deliverTxIsr, generatedIsr) { + e.logger.Debug("ISR Mismatch", "given_isr", deliverTxIsr, "generated_isr", generatedIsr) + _ = req.Value.(*abci.Request_DeliverTx).DeliverTx.Tx + go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + } + } + if txRes.Code == abci.CodeTypeOK { validTxs++ } else { @@ -301,18 +329,38 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t if err != nil { return nil, err } + isr, err := e.getAppHash() + if err != nil { + return nil, err + } + ISRs = append(ISRs, isr) + 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()) } + isr, err := e.getAppHash() + if err != nil { + return nil, err + } + ISRs = append(ISRs, isr) } 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 + } + ISRs = append(ISRs, isr) + if block.Data.IntermediateStateRoots.RawRootsList == nil { + // Block producer: Initial ISRs generated here + block.Data.IntermediateStateRoots.RawRootsList = ISRs + } return abciResponses, nil } @@ -367,6 +415,14 @@ func (e *BlockExecutor) publishEvents(resp *tmstate.ABCIResponses, block *types. return err } +func (e *BlockExecutor) getAppHash() ([]byte, error) { + isrResp, err := e.proxyApp.GetAppHashSync(abci.RequestGetAppHash{}) + if err != nil { + return nil, err + } + return isrResp.AppHash, nil +} + func toOptimintTxs(txs tmtypes.Txs) types.Txs { optiTxs := make(types.Txs, len(txs)) for i := range txs { From 49b43b4e359bfb2381930577d8bdecc82bd4b9f3 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 00:49:52 -0400 Subject: [PATCH 03/10] Add new abci method in mocks all across tests --- node/integration_test.go | 4 ++++ rpc/client/client_test.go | 4 ++++ rpc/json/service_test.go | 2 ++ state/executor_test.go | 2 ++ 4 files changed, 12 insertions(+) diff --git a/node/integration_test.go b/node/integration_test.go index aa2f6c895d..1fb3d70e1f 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -40,6 +40,8 @@ func TestAggregatorMode(t *testing.T) { app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) key, _, _ := crypto.GenerateEd25519Key(rand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) @@ -289,6 +291,8 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{Events: generateEventsWithOneEventIsr(t)}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{Events: generateEventsWithOneEventIsr(t)}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) deliverTxEvents := generateEventsWithOneEventIsr(t) if isMalicious { diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index 7e3f8ab072..b9f371cc9c 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -420,6 +420,8 @@ func TestTx(t *testing.T) { mockApp.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) mockApp.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) mockApp.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) + mockApp.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + mockApp.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) err = rpc.node.Start() require.NoError(err) @@ -633,6 +635,8 @@ func TestValidatorSetHandling(t *testing.T) { app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) key, _, _ := crypto.GenerateEd25519Key(crand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(crand.Reader) diff --git a/rpc/json/service_test.go b/rpc/json/service_test.go index d901591f78..5e33804b2f 100644 --- a/rpc/json/service_test.go +++ b/rpc/json/service_test.go @@ -275,6 +275,8 @@ func getRPC(t *testing.T) (*mocks.Application, *client.Client) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{ GasWanted: 1000, GasUsed: 1000, diff --git a/state/executor_test.go b/state/executor_test.go index 4518709849..2ebc75fef5 100644 --- a/state/executor_test.go +++ b/state/executor_test.go @@ -80,6 +80,8 @@ func TestApplyBlock(t *testing.T) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) var mockAppHash [32]byte _, err := rand.Read(mockAppHash[:]) require.NoError(err) From f231e9caf039dca53a870552e4abbaa08c80d723 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 01:45:59 -0400 Subject: [PATCH 04/10] All tests work now --- node/integration_test.go | 11 +++++------ state/executor.go | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/node/integration_test.go b/node/integration_test.go index 1fb3d70e1f..2064dfb049 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -205,7 +205,6 @@ func TestFraudProofGenerationTrigger(t *testing.T) { for i, app := range apps { app.AssertNumberOfCalls(t, "DeliverTx", clientNodes) - app.AssertNumberOfCalls(t, "GenerateFraudProof", 1) app.AssertExpectations(t) // assert that we have most of the blocks from aggregator @@ -291,8 +290,8 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{Events: generateEventsWithOneEventIsr(t)}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{Events: generateEventsWithOneEventIsr(t)}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) - app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: []byte{1, 2, 3, 4}}) + // app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) deliverTxEvents := generateEventsWithOneEventIsr(t) if isMalicious { @@ -302,9 +301,9 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili wg.Done() }) - if isMalicious && !aggregator { - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) - } + // if isMalicious && !aggregator { + // app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + // } signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) node, err := NewNode( diff --git a/state/executor.go b/state/executor.go index 6d96f69aea..9b6e1973c9 100644 --- a/state/executor.go +++ b/state/executor.go @@ -284,19 +284,19 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t if r, ok := res.Value.(*abci.Response_DeliverTx); ok { txRes := r.DeliverTx - if currentIsrs != nil { - generatedIsr, err := e.getAppHash() - if err != nil { - return - } - deliverTxIsr := currentIsrs[currentIsrIndex] - currentIsrIndex++ - if !bytes.Equal(deliverTxIsr, generatedIsr) { - e.logger.Debug("ISR Mismatch", "given_isr", deliverTxIsr, "generated_isr", generatedIsr) - _ = req.Value.(*abci.Request_DeliverTx).DeliverTx.Tx - go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) - } - } + // if currentIsrs != nil { + // generatedIsr, err := e.getAppHash() + // if err != nil { + // return + // } + // deliverTxIsr := currentIsrs[currentIsrIndex] + // currentIsrIndex++ + // if !bytes.Equal(deliverTxIsr, generatedIsr) { + // e.logger.Debug("ISR Mismatch", "given_isr", deliverTxIsr, "generated_isr", generatedIsr) + // _ = req.Value.(*abci.Request_DeliverTx).DeliverTx.Tx + // go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + // } + // } if txRes.Code == abci.CodeTypeOK { validTxs++ From d213667737e6aaee7d9e604e44c7ed3578b7f897 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 02:02:15 -0400 Subject: [PATCH 05/10] Add fraudproof trigger --- state/executor.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/state/executor.go b/state/executor.go index 9b6e1973c9..269354af17 100644 --- a/state/executor.go +++ b/state/executor.go @@ -283,21 +283,6 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t e.proxyApp.SetResponseCallback(func(req *abci.Request, res *abci.Response) { if r, ok := res.Value.(*abci.Response_DeliverTx); ok { txRes := r.DeliverTx - - // if currentIsrs != nil { - // generatedIsr, err := e.getAppHash() - // if err != nil { - // return - // } - // deliverTxIsr := currentIsrs[currentIsrIndex] - // currentIsrIndex++ - // if !bytes.Equal(deliverTxIsr, generatedIsr) { - // e.logger.Debug("ISR Mismatch", "given_isr", deliverTxIsr, "generated_isr", generatedIsr) - // _ = req.Value.(*abci.Request_DeliverTx).DeliverTx.Tx - // go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) - // } - // } - if txRes.Code == abci.CodeTypeOK { validTxs++ } else { @@ -334,6 +319,7 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) + e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) currentIsrIndex++ for _, tx := range block.Data.Txs { @@ -346,6 +332,8 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) + e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + currentIsrIndex++ } abciResponses.EndBlock, err = e.proxyApp.EndBlockSync(abci.RequestEndBlock{Height: int64(block.Header.Height)}) @@ -357,6 +345,7 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) + e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) if block.Data.IntermediateStateRoots.RawRootsList == nil { // Block producer: Initial ISRs generated here block.Data.IntermediateStateRoots.RawRootsList = ISRs @@ -365,6 +354,16 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return abciResponses, nil } +func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) { + if currentIsrs != nil { + stateIsr := currentIsrs[index] + if !bytes.Equal(stateIsr, generatedIsr) { + e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) + go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + } + } +} + func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte { lastABCICommit := abciconv.ToABCICommit(lastCommit) if len(lastCommit.Signatures) == 1 { From 1d9c38958868ec637b99ab2ebf7aac81095369ab Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 02:10:12 -0400 Subject: [PATCH 06/10] Remove fraud trigger integration test --- node/integration_test.go | 114 +++------------------------------------ 1 file changed, 8 insertions(+), 106 deletions(-) diff --git a/node/integration_test.go b/node/integration_test.go index 2064dfb049..72a5cad84a 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -91,7 +91,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { var wg sync.WaitGroup clientNodes := 4 - nodes, apps := createNodes(clientNodes+1, false, &wg, t) + nodes, apps := createNodes(clientNodes+1, &wg, t) wg.Add((clientNodes + 1) * clientNodes) for _, n := range nodes { @@ -161,84 +161,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { } } -func TestFraudProofGenerationTrigger(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - var wg sync.WaitGroup - clientNodes := 4 - - nodes, apps := createNodes(clientNodes+1, true, &wg, t) - - wg.Add((clientNodes + 1) * clientNodes) - for _, n := range nodes { - require.NoError(n.Start()) - } - - time.Sleep(1 * time.Second) - - for i := 1; i < len(nodes); i++ { - data := strconv.Itoa(i) + time.Now().String() - require.NoError(nodes[i].P2P.GossipTx(context.TODO(), []byte(data))) - } - - timeout := time.NewTimer(time.Second * 30) - doneChan := make(chan struct{}) - go func() { - defer close(doneChan) - wg.Wait() - }() - select { - case <-doneChan: - case <-timeout.C: - t.FailNow() - } - - for _, n := range nodes { - require.NoError(n.Stop()) - } - aggApp := apps[0] - apps = apps[1:] - - aggApp.AssertNumberOfCalls(t, "DeliverTx", clientNodes) - aggApp.AssertExpectations(t) - - for i, app := range apps { - app.AssertNumberOfCalls(t, "DeliverTx", clientNodes) - app.AssertExpectations(t) - - // assert that we have most of the blocks from aggregator - beginCnt := 0 - endCnt := 0 - commitCnt := 0 - for _, call := range app.Calls { - switch call.Method { - case "BeginBlock": - beginCnt++ - case "EndBlock": - endCnt++ - case "Commit": - commitCnt++ - } - } - aggregatorHeight := nodes[0].Store.Height() - adjustedHeight := int(aggregatorHeight - 3) // 3 is completely arbitrary - assert.GreaterOrEqual(beginCnt, adjustedHeight) - assert.GreaterOrEqual(endCnt, adjustedHeight) - assert.GreaterOrEqual(commitCnt, adjustedHeight) - - // assert that all blocks known to node are same as produced by aggregator - for h := uint64(1); h <= nodes[i].Store.Height(); h++ { - nodeBlock, err := nodes[i].Store.LoadBlock(h) - require.NoError(err) - aggBlock, err := nodes[0].Store.LoadBlock(h) - require.NoError(err) - assert.Equal(aggBlock, nodeBlock) - } - } -} - -func createNodes(num int, isAggregatorMalicious bool, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { +func createNodes(num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { t.Helper() // create keys first, as they are required for P2P connections @@ -252,15 +175,15 @@ func createNodes(num int, isAggregatorMalicious bool, wg *sync.WaitGroup, t *tes dalc := &mockda.MockDataAvailabilityLayerClient{} _ = dalc.Init(nil, store.NewDefaultInMemoryKVStore(), log.TestingLogger()) _ = dalc.Start() - nodes[0], apps[0] = createNode(0, isAggregatorMalicious, true, dalc, keys, wg, t) + nodes[0], apps[0] = createNode(0, true, dalc, keys, wg, t) for i := 1; i < num; i++ { - nodes[i], apps[i] = createNode(i, isAggregatorMalicious, false, dalc, keys, wg, t) + nodes[i], apps[i] = createNode(i, false, dalc, keys, wg, t) } return nodes, apps } -func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { +func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { t.Helper() require := require.New(t) // nodes will listen on consecutive ports on local interface @@ -287,24 +210,14 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili app := &mocks.Application{} app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{}) app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) - app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{Events: generateEventsWithOneEventIsr(t)}) - app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{Events: generateEventsWithOneEventIsr(t)}) + app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) + app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: []byte{1, 2, 3, 4}}) - // app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) - - deliverTxEvents := generateEventsWithOneEventIsr(t) - if isMalicious { - deliverTxEvents[0].Attributes[0].Value = []byte{9, 8, 7, 6} - } - app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{Events: deliverTxEvents}).Run(func(args mock.Arguments) { + app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}).Run(func(args mock.Arguments) { wg.Done() }) - // if isMalicious && !aggregator { - // app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) - // } - signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) node, err := NewNode( context.Background(), @@ -328,14 +241,3 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili return node, app } - -func generateEventsWithOneEventIsr(t *testing.T) []abci.Event { - t.Helper() - return []abci.Event{{ - Type: "isr", - Attributes: []abci.EventAttribute{{ - Key: []byte("isr"), - Value: []byte{1, 2, 3, 4}, - }}, - }} -} From 44822f0b3dd0438b737bc475932831811d0a696c Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 02:11:48 -0400 Subject: [PATCH 07/10] Remove getAppHash from mock.on --- node/integration_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/node/integration_test.go b/node/integration_test.go index 72a5cad84a..58908d1d84 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -41,7 +41,6 @@ func TestAggregatorMode(t *testing.T) { app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) key, _, _ := crypto.GenerateEd25519Key(rand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(rand.Reader) From f7969fe61f86c654278a25827d4c8cf5b81ce328 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 02:38:11 -0400 Subject: [PATCH 08/10] Write a fraudproof integration test --- node/integration_test.go | 101 ++++++++++++++++++++++++++++++++++++--- state/executor.go | 2 +- state/executor_test.go | 4 +- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/node/integration_test.go b/node/integration_test.go index 58908d1d84..91ba7c6a70 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -90,7 +90,7 @@ func TestTxGossipingAndAggregation(t *testing.T) { var wg sync.WaitGroup clientNodes := 4 - nodes, apps := createNodes(clientNodes+1, &wg, t) + nodes, apps := createNodes(false, clientNodes+1, &wg, t) wg.Add((clientNodes + 1) * clientNodes) for _, n := range nodes { @@ -160,7 +160,88 @@ func TestTxGossipingAndAggregation(t *testing.T) { } } -func createNodes(num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { +func TestFraudProofTrigger(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + var wg sync.WaitGroup + clientNodes := 4 + nodes, apps := createNodes(true, clientNodes+1, &wg, t) + + wg.Add((clientNodes + 1) * clientNodes) + for _, n := range nodes { + require.NoError(n.Start()) + } + + time.Sleep(1 * time.Second) + + for i := 1; i < len(nodes); i++ { + data := strconv.Itoa(i) + time.Now().String() + require.NoError(nodes[i].P2P.GossipTx(context.TODO(), []byte(data))) + } + + timeout := time.NewTimer(time.Second * 30) + doneChan := make(chan struct{}) + go func() { + defer close(doneChan) + wg.Wait() + }() + select { + case <-doneChan: + case <-timeout.C: + t.FailNow() + } + + for _, n := range nodes { + require.NoError(n.Stop()) + } + aggApp := apps[0] + apps = apps[1:] + + aggApp.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + aggApp.AssertExpectations(t) + + for i, app := range apps { + app.AssertNumberOfCalls(t, "DeliverTx", clientNodes) + app.AssertExpectations(t) + + // assert that we have most of the blocks from aggregator + beginCnt := 0 + endCnt := 0 + commitCnt := 0 + generateFraudProofCnt := 0 + for _, call := range app.Calls { + switch call.Method { + case "BeginBlock": + beginCnt++ + case "EndBlock": + endCnt++ + case "Commit": + commitCnt++ + case "GenerateFraudProof": + generateFraudProofCnt++ + } + } + aggregatorHeight := nodes[0].Store.Height() + adjustedHeight := int(aggregatorHeight - 3) // 3 is completely arbitrary + assert.GreaterOrEqual(beginCnt, adjustedHeight) + assert.GreaterOrEqual(endCnt, adjustedHeight) + assert.GreaterOrEqual(commitCnt, adjustedHeight) + + assert.Equal(generateFraudProofCnt, beginCnt+endCnt+clientNodes) + + // assert that all blocks known to node are same as produced by aggregator + for h := uint64(1); h <= nodes[i].Store.Height(); h++ { + nodeBlock, err := nodes[i].Store.LoadBlock(h) + require.NoError(err) + aggBlock, err := nodes[0].Store.LoadBlock(h) + require.NoError(err) + assert.Equal(aggBlock, nodeBlock) + } + } +} + +func createNodes(isMalicious bool, num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.Application) { t.Helper() // create keys first, as they are required for P2P connections @@ -174,15 +255,15 @@ func createNodes(num int, wg *sync.WaitGroup, t *testing.T) ([]*Node, []*mocks.A dalc := &mockda.MockDataAvailabilityLayerClient{} _ = dalc.Init(nil, store.NewDefaultInMemoryKVStore(), log.TestingLogger()) _ = dalc.Start() - nodes[0], apps[0] = createNode(0, true, dalc, keys, wg, t) + nodes[0], apps[0] = createNode(0, isMalicious, true, dalc, keys, wg, t) for i := 1; i < num; i++ { - nodes[i], apps[i] = createNode(i, false, dalc, keys, wg, t) + nodes[i], apps[i] = createNode(i, isMalicious, false, dalc, keys, wg, t) } return nodes, apps } -func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { +func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabilityLayerClient, keys []crypto.PrivKey, wg *sync.WaitGroup, t *testing.T) (*Node, *mocks.Application) { t.Helper() require := require.New(t) // nodes will listen on consecutive ports on local interface @@ -212,7 +293,15 @@ func createNode(n int, aggregator bool, dalc da.DataAvailabilityLayerClient, key app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) - app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: []byte{1, 2, 3, 4}}) + if isMalicious && aggregator { + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: []byte{9, 8, 7, 6}}) + } else { + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{AppHash: []byte{1, 2, 3, 4}}) + } + + if isMalicious && !aggregator { + app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + } app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}).Run(func(args mock.Arguments) { wg.Done() }) diff --git a/state/executor.go b/state/executor.go index 269354af17..2d355ddfe4 100644 --- a/state/executor.go +++ b/state/executor.go @@ -359,7 +359,7 @@ func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs stateIsr := currentIsrs[index] if !bytes.Equal(stateIsr, generatedIsr) { e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) - go e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) } } } diff --git a/state/executor_test.go b/state/executor_test.go index 2ebc75fef5..b1a9db65b8 100644 --- a/state/executor_test.go +++ b/state/executor_test.go @@ -80,11 +80,13 @@ func TestApplyBlock(t *testing.T) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) - app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) var mockAppHash [32]byte _, err := rand.Read(mockAppHash[:]) require.NoError(err) + app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{ + AppHash: mockAppHash[:], + }) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{ Data: mockAppHash[:], }) From 9ca852cbedc90fc6520618c6a7e7130319448c71 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 09:49:36 -0400 Subject: [PATCH 09/10] Run golang linter --- state/executor.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/state/executor.go b/state/executor.go index 2d355ddfe4..f45083c367 100644 --- a/state/executor.go +++ b/state/executor.go @@ -319,7 +319,10 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) - e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + if err != nil { + return nil, err + } currentIsrIndex++ for _, tx := range block.Data.Txs { @@ -332,7 +335,10 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) - e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + if err != nil { + return nil, err + } currentIsrIndex++ } @@ -345,7 +351,10 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return nil, err } ISRs = append(ISRs, isr) - e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + err = e.checkFraudProofTrigger(isr, currentIsrs, currentIsrIndex) + if err != nil { + return nil, err + } if block.Data.IntermediateStateRoots.RawRootsList == nil { // Block producer: Initial ISRs generated here block.Data.IntermediateStateRoots.RawRootsList = ISRs @@ -354,14 +363,18 @@ func (e *BlockExecutor) execute(ctx context.Context, state types.State, block *t return abciResponses, nil } -func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) { +func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs [][]byte, index int) error { if currentIsrs != nil { stateIsr := currentIsrs[index] if !bytes.Equal(stateIsr, generatedIsr) { e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) - e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + _, err := e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + if err != nil { + return err + } } } + return nil } func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte { From 016b3a1866f25f6053f46951c4f7a968c0c4cd20 Mon Sep 17 00:00:00 2001 From: Manav Aggarwal Date: Wed, 24 Aug 2022 09:54:20 -0400 Subject: [PATCH 10/10] Replace Generate with trigger --- node/integration_test.go | 10 +++++----- rpc/client/client_test.go | 4 ++-- state/executor.go | 2 +- state/executor_test.go | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/node/integration_test.go b/node/integration_test.go index 91ba7c6a70..9b201c5d01 100644 --- a/node/integration_test.go +++ b/node/integration_test.go @@ -209,7 +209,7 @@ func TestFraudProofTrigger(t *testing.T) { beginCnt := 0 endCnt := 0 commitCnt := 0 - generateFraudProofCnt := 0 + triggerFraudProofGenerationModeCnt := 0 for _, call := range app.Calls { switch call.Method { case "BeginBlock": @@ -218,8 +218,8 @@ func TestFraudProofTrigger(t *testing.T) { endCnt++ case "Commit": commitCnt++ - case "GenerateFraudProof": - generateFraudProofCnt++ + case "TriggerFraudProofGenerationMode": + triggerFraudProofGenerationModeCnt++ } } aggregatorHeight := nodes[0].Store.Height() @@ -228,7 +228,7 @@ func TestFraudProofTrigger(t *testing.T) { assert.GreaterOrEqual(endCnt, adjustedHeight) assert.GreaterOrEqual(commitCnt, adjustedHeight) - assert.Equal(generateFraudProofCnt, beginCnt+endCnt+clientNodes) + assert.Equal(triggerFraudProofGenerationModeCnt, beginCnt+endCnt+clientNodes) // assert that all blocks known to node are same as produced by aggregator for h := uint64(1); h <= nodes[i].Store.Height(); h++ { @@ -300,7 +300,7 @@ func createNode(n int, isMalicious bool, aggregator bool, dalc da.DataAvailabili } if isMalicious && !aggregator { - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + app.On("TriggerFraudProofGenerationMode", mock.Anything).Return(abci.ResponseTriggerFraudProofGenerationMode{}) } app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}).Run(func(args mock.Arguments) { wg.Done() diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index b9f371cc9c..10fe3217b9 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -421,7 +421,7 @@ func TestTx(t *testing.T) { mockApp.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) mockApp.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{}) mockApp.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) - mockApp.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + mockApp.On("TriggerFraudProofGenerationMode", mock.Anything).Return(abci.ResponseTriggerFraudProofGenerationMode{}) err = rpc.node.Start() require.NoError(err) @@ -636,7 +636,7 @@ func TestValidatorSetHandling(t *testing.T) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{}) - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + app.On("TriggerFraudProofGenerationMode", mock.Anything).Return(abci.ResponseTriggerFraudProofGenerationMode{}) key, _, _ := crypto.GenerateEd25519Key(crand.Reader) signingKey, _, _ := crypto.GenerateEd25519Key(crand.Reader) diff --git a/state/executor.go b/state/executor.go index f45083c367..af9fd33f68 100644 --- a/state/executor.go +++ b/state/executor.go @@ -368,7 +368,7 @@ func (e *BlockExecutor) checkFraudProofTrigger(generatedIsr []byte, currentIsrs stateIsr := currentIsrs[index] if !bytes.Equal(stateIsr, generatedIsr) { e.logger.Debug("ISR Mismatch", "given_isr", stateIsr, "generated_isr", generatedIsr) - _, err := e.proxyApp.GenerateFraudProofSync(abci.RequestGenerateFraudProof{}) + _, err := e.proxyApp.TriggerFraudProofGenerationModeSync(abci.RequestTriggerFraudProofGenerationMode{}) if err != nil { return err } diff --git a/state/executor_test.go b/state/executor_test.go index b1a9db65b8..9b851f6d1d 100644 --- a/state/executor_test.go +++ b/state/executor_test.go @@ -80,7 +80,7 @@ func TestApplyBlock(t *testing.T) { app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) app.On("DeliverTx", mock.Anything).Return(abci.ResponseDeliverTx{}) app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}) - app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{}) + app.On("TriggerFraudProofGenerationMode", mock.Anything).Return(abci.ResponseTriggerFraudProofGenerationMode{}) var mockAppHash [32]byte _, err := rand.Read(mockAppHash[:]) require.NoError(err)