core: save application logs for native persist

This commit is contained in:
Evgenii Stratonikov 2020-06-18 14:19:55 +03:00
parent 3894b6db9f
commit 295d8fc70e
3 changed files with 55 additions and 5 deletions

View file

@ -363,7 +363,20 @@ func (bc *Blockchain) notificationDispatcher() {
// We don't want to waste time looping through transactions when there are no // We don't want to waste time looping through transactions when there are no
// subscribers. // subscribers.
if len(txFeed) != 0 || len(notificationFeed) != 0 || len(executionFeed) != 0 { 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 { for _, tx := range event.block.Transactions {
aer := event.appExecResults[aerIdx] aer := event.appExecResults[aerIdx]
if !aer.TxHash.Equals(tx.Hash()) { 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. // and all tests are in place, we can make a more optimized and cleaner implementation.
func (bc *Blockchain) storeBlock(block *block.Block) error { func (bc *Blockchain) storeBlock(block *block.Block) error {
cache := dao.NewCached(bc.dao) 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 { if err := cache.StoreAsBlock(block); err != nil {
return err return err
} }
@ -565,6 +578,19 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
} else if _, err := systemInterop.DAO.Persist(); err != nil { } else if _, err := systemInterop.DAO.Persist(); err != nil {
return errors.Wrap(err, "can't persist `onPersist` changes") 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 { for _, tx := range block.Transactions {

View file

@ -257,13 +257,16 @@ func TestSubscriptions(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Eventually(t, func() bool { return len(blockCh) != 0 }, time.Second, 10*time.Millisecond) require.Eventually(t, func() bool { return len(blockCh) != 0 }, time.Second, 10*time.Millisecond)
assert.Empty(t, notificationCh) assert.Empty(t, notificationCh)
assert.Empty(t, executionCh) assert.Len(t, executionCh, 1)
assert.Empty(t, txCh) assert.Empty(t, txCh)
b := <-blockCh b := <-blockCh
assert.Equal(t, blocks[0], b) assert.Equal(t, blocks[0], b)
assert.Empty(t, blockCh) assert.Empty(t, blockCh)
aer := <-executionCh
assert.Equal(t, b.Hash(), aer.TxHash)
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
emit.Bytes(script.BinWriter, []byte("yay!")) emit.Bytes(script.BinWriter, []byte("yay!"))
emit.Syscall(script.BinWriter, "System.Runtime.Notify") emit.Syscall(script.BinWriter, "System.Runtime.Notify")
@ -308,6 +311,17 @@ func TestSubscriptions(t *testing.T) {
require.Equal(t, invBlock, b) require.Equal(t, invBlock, b)
assert.Empty(t, blockCh) 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. // Follow in-block transaction order.
for _, txExpected := range invBlock.Transactions { for _, txExpected := range invBlock.Transactions {
tx := <-txCh tx := <-txCh

View file

@ -97,8 +97,18 @@ func TestSubscriptions(t *testing.T) {
for _, b := range getTestBlocks(t) { for _, b := range getTestBlocks(t) {
require.NoError(t, chain.AddBlock(b)) 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) 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) require.Equal(t, response.ExecutionEventID, resp.Event)
for { for {
resp := getNotification(t, respMsgs) resp := getNotification(t, respMsgs)
@ -109,7 +119,7 @@ func TestSubscriptions(t *testing.T) {
break break
} }
} }
resp := getNotification(t, respMsgs) resp = getNotification(t, respMsgs)
require.Equal(t, response.BlockEventID, resp.Event) require.Equal(t, response.BlockEventID, resp.Event)
} }