From 295d8fc70eb6694ab5e30f4f3845e56dc67ba80b Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 18 Jun 2020 14:19:55 +0300 Subject: [PATCH] core: save application logs for native persist --- pkg/core/blockchain.go | 30 +++++++++++++++++++++++++++-- pkg/core/blockchain_test.go | 16 ++++++++++++++- pkg/rpc/server/subscription_test.go | 14 ++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 6beb28af2..620e330f1 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -363,7 +363,20 @@ func (bc *Blockchain) notificationDispatcher() { // We don't want to waste time looping through transactions when there are no // subscribers. if len(txFeed) != 0 || len(notificationFeed) != 0 || len(executionFeed) != 0 { - var aerIdx int + aer := event.appExecResults[0] + if !aer.TxHash.Equals(event.block.Hash()) { + panic("inconsistent application execution results") + } + for ch := range executionFeed { + ch <- aer + } + for i := range aer.Events { + for ch := range notificationFeed { + ch <- &aer.Events[i] + } + } + + aerIdx := 1 for _, tx := range event.block.Transactions { aer := event.appExecResults[aerIdx] if !aer.TxHash.Equals(tx.Hash()) { @@ -547,7 +560,7 @@ func (bc *Blockchain) processHeader(h *block.Header, batch storage.Batch, header // and all tests are in place, we can make a more optimized and cleaner implementation. func (bc *Blockchain) storeBlock(block *block.Block) error { cache := dao.NewCached(bc.dao) - appExecResults := make([]*state.AppExecResult, 0, len(block.Transactions)) + appExecResults := make([]*state.AppExecResult, 0, 1+len(block.Transactions)) if err := cache.StoreAsBlock(block); err != nil { return err } @@ -565,6 +578,19 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { } else if _, err := systemInterop.DAO.Persist(); err != nil { return errors.Wrap(err, "can't persist `onPersist` changes") } + aer := &state.AppExecResult{ + TxHash: block.Hash(), // application logs can be retrieved by block hash + Trigger: trigger.System, + VMState: v.State(), + GasConsumed: v.GasConsumed(), + Stack: v.Estack().ToContractParameters(), + Events: systemInterop.Notifications, + } + appExecResults = append(appExecResults, aer) + err := cache.PutAppExecResult(aer) + if err != nil { + return errors.Wrap(err, "failed to Store notifications") + } } for _, tx := range block.Transactions { diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 1e34150ea..3cc4c6e11 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -257,13 +257,16 @@ func TestSubscriptions(t *testing.T) { require.NoError(t, err) require.Eventually(t, func() bool { return len(blockCh) != 0 }, time.Second, 10*time.Millisecond) assert.Empty(t, notificationCh) - assert.Empty(t, executionCh) + assert.Len(t, executionCh, 1) assert.Empty(t, txCh) b := <-blockCh assert.Equal(t, blocks[0], b) assert.Empty(t, blockCh) + aer := <-executionCh + assert.Equal(t, b.Hash(), aer.TxHash) + script := io.NewBufBinWriter() emit.Bytes(script.BinWriter, []byte("yay!")) emit.Syscall(script.BinWriter, "System.Runtime.Notify") @@ -308,6 +311,17 @@ func TestSubscriptions(t *testing.T) { require.Equal(t, invBlock, b) assert.Empty(t, blockCh) + exec := <-executionCh + require.Equal(t, b.Hash(), exec.TxHash) + require.Equal(t, exec.VMState, "HALT") + + // 3 burn events for every tx and 1 mint for primary node + require.True(t, len(notificationCh) >= 4) + for i := 0; i < 4; i++ { + notif := <-notificationCh + require.Equal(t, bc.contracts.GAS.Hash, notif.ScriptHash) + } + // Follow in-block transaction order. for _, txExpected := range invBlock.Transactions { tx := <-txCh diff --git a/pkg/rpc/server/subscription_test.go b/pkg/rpc/server/subscription_test.go index c11265cfe..850b219de 100644 --- a/pkg/rpc/server/subscription_test.go +++ b/pkg/rpc/server/subscription_test.go @@ -97,8 +97,18 @@ func TestSubscriptions(t *testing.T) { for _, b := range getTestBlocks(t) { require.NoError(t, chain.AddBlock(b)) - for range b.Transactions { + resp := getNotification(t, respMsgs) + require.Equal(t, response.ExecutionEventID, resp.Event) + for { resp := getNotification(t, respMsgs) + if resp.Event != response.NotificationEventID { + break + } + } + for i := 0; i < len(b.Transactions); i++ { + if i > 0 { + resp = getNotification(t, respMsgs) + } require.Equal(t, response.ExecutionEventID, resp.Event) for { resp := getNotification(t, respMsgs) @@ -109,7 +119,7 @@ func TestSubscriptions(t *testing.T) { break } } - resp := getNotification(t, respMsgs) + resp = getNotification(t, respMsgs) require.Equal(t, response.BlockEventID, resp.Event) }