-
Notifications
You must be signed in to change notification settings - Fork 2
/
deliver.go
136 lines (121 loc) · 4.19 KB
/
deliver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package deliver
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/fibonacci-chain/fbc/x/evm/watcher"
"github.com/fibonacci-chain/fbc/app/refund"
sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
bam "github.com/fibonacci-chain/fbc/libs/system/trace"
"github.com/fibonacci-chain/fbc/x/evm/keeper"
"github.com/fibonacci-chain/fbc/x/evm/txs/base"
"github.com/fibonacci-chain/fbc/x/evm/types"
)
type Tx struct {
*base.Tx
}
func NewTx(config base.Config) *Tx {
return &Tx{
Tx: base.NewTx(config),
}
}
// SaveTx since the txCount is used by the stateDB, and a simulated tx is run only on the node it's submitted to,
// then this will cause the txCount/stateDB of the node that ran the simulated tx to be different with the
// other nodes, causing a consensus error
func (tx *Tx) SaveTx(msg *types.MsgEthereumTx) {
tx.AnalyzeStart(bam.SaveTx)
defer tx.AnalyzeStop(bam.SaveTx)
// Prepare db for logs
tx.StateTransition.Csdb.Prepare(*tx.StateTransition.TxHash, tx.Keeper.Bhash, tx.Keeper.TxCount)
tx.StateTransition.Csdb.SetLogSize(tx.Keeper.LogSize)
tx.Keeper.TxCount++
if tx.Ctx.ParaMsg() != nil {
tx.Ctx.ParaMsg().HasRunEvmTx = true
}
}
func (tx *Tx) GetSenderAccount() authexported.Account {
pm := tx.Keeper.GenerateCSDBParams()
infCtx := tx.Ctx
infCtx.SetGasMeter(sdk.NewInfiniteGasMeter())
return pm.AccountKeeper.GetAccount(infCtx, tx.StateTransition.Sender.Bytes())
}
// resetWatcher when panic reset watcher
func (tx *Tx) resetWatcher(account authexported.Account) {
// delete account which is already in Watcher.batch
if account != nil && tx.Ctx.GetWatcher().Enabled() {
tx.Ctx.GetWatcher().DeleteAccount(account)
}
}
// refundFeesWatcher fix account balance in watcher with refund fees
func (tx *Tx) refundFeesWatcher(account authexported.Account, ethereumTx *types.MsgEthereumTx) {
// fix account balance in watcher with refund fees
if account == nil || !tx.Ctx.GetWatcher().Enabled() {
return
}
defer func() {
//panic was not allowed in this function
if e := recover(); e != nil {
tx.Ctx.Logger().Error(fmt.Sprintf("recovered panic at func refundFeesWatcher %v\n", e))
}
}()
gasConsumed := tx.Ctx.GasMeter().GasConsumed()
gasLimit := ethereumTx.Data.GasLimit
if gasConsumed >= gasLimit {
return
}
fixedFees := refund.CalculateRefundFees(gasConsumed, ethereumTx.GetFee(), ethereumTx.Data.Price)
coins := account.GetCoins().Add2(fixedFees)
account.SetCoins(coins) //ignore err, no err will be returned in SetCoins
tx.Ctx.GetWatcher().SaveAccount(account)
}
func (tx *Tx) Transition(config types.ChainConfig) (result base.Result, err error) {
result, err = tx.Tx.Transition(config)
if result.InnerTxs != nil {
tx.Keeper.AddInnerTx(tx.StateTransition.TxHash.Hex(), result.InnerTxs)
}
if result.Erc20Contracts != nil {
tx.Keeper.AddContract(result.Erc20Contracts)
}
return
}
func (tx *Tx) Commit(msg *types.MsgEthereumTx, result *base.Result) {
// update block bloom filter
if tx.Ctx.ParaMsg() == nil {
tx.Keeper.Bloom.Or(tx.Keeper.Bloom, result.ExecResult.Bloom)
tx.Keeper.Watcher.SaveTransactionReceipt(watcher.TransactionSuccess,
msg, *tx.StateTransition.TxHash,
tx.Keeper.Watcher.GetEvmTxIndex(), result.ResultData, tx.Ctx.GasMeter().GasConsumed())
} else {
// async mod goes immediately
index := tx.Keeper.LogsManages.Set(keeper.TxResult{
ResultData: result.ResultData,
})
tx.Ctx.ParaMsg().LogIndex = index
}
tx.Keeper.LogSize = tx.StateTransition.Csdb.GetLogSize()
if msg.Data.Recipient == nil && tx.Ctx.GetWatcher().Enabled() {
tx.StateTransition.Csdb.IteratorCode(func(addr common.Address, c types.CacheCode) bool {
tx.Ctx.GetWatcher().SaveContractCode(addr, c.Code, uint64(tx.Ctx.BlockHeight()))
tx.Ctx.GetWatcher().SaveContractCodeByHash(c.CodeHash, c.Code)
return true
})
}
}
func (tx *Tx) FinalizeWatcher(msg *types.MsgEthereumTx, err error, panic bool) {
if !tx.Ctx.GetWatcher().Enabled() {
return
}
account := tx.GetSenderAccount()
if panic {
tx.resetWatcher(account)
return
}
tx.refundFeesWatcher(account, msg)
// handle error
if err != nil {
// reset watcher
tx.resetWatcher(account)
return
}
tx.Ctx.GetWatcher().Finalize()
}