forked from fractal-platform/fractal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tx_pool.go
138 lines (113 loc) · 3.89 KB
/
tx_pool.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
137
138
package transaction
import (
"errors"
"reflect"
"github.com/fractal-platform/fractal/chain"
"github.com/fractal-platform/fractal/common"
"github.com/fractal-platform/fractal/core/config"
"github.com/fractal-platform/fractal/core/pool"
"github.com/fractal-platform/fractal/core/types"
"github.com/fractal-platform/fractal/transaction/txexec"
"github.com/fractal-platform/fractal/utils/log"
)
var TransactionType = reflect.TypeOf(types.Transaction{})
var (
// ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender = errors.New("invalid sender")
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit")
// ErrNegativeValue is a sanity error to ensure noone is able to specify a
// transaction with a negative value.
ErrNegativeValue = errors.New("negative value")
// ErrOversizedData is returned if the input data of a transaction is greater
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.
ErrOversizedData = errors.New("oversized data")
// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas limit * price + value")
)
type TxHelper struct {
signer types.Signer
}
func (h *TxHelper) Reset(p pool.Pool, newHead *types.Block) {
// Traversing the transactions in the block, comparing the nonce
for _, newTx := range newHead.Body.Transactions {
address, _ := types.Sender(h.signer, newTx)
if newTx.Nonce() >= p.StateUnsafe().GetNonce(address) {
// Put into the p, this happens only for non-local blocks
p.AddUnsafe([]pool.Element{newTx}, false)
}
}
}
func (h *TxHelper) Validate(p pool.Pool, ele pool.Element, currentState pool.StateDB, blockChain pool.BlockChain) error {
tx := (ele).(*types.Transaction)
if !tx.Broadcast() {
return pool.ErrIsNotAPacker
}
from, err := h.Sender(ele)
if err != nil {
return err
}
if tx.Size() > 32*1024 {
return ErrOversizedData
}
if tx.Value().Sign() < 0 {
return ErrNegativeValue
}
if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
return ErrInsufficientFunds
}
intrGas, err := txexec.IntrinsicGas(tx.Data(), tx.To() == nil)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return ErrIntrinsicGas
}
if blockChain.CurrentBlock().Header.GasLimit < tx.Gas() {
return ErrGasLimit
}
if stateDB, _, ok := p.GetStateBeforeCacheHeight(); ok {
if stateDB.GetNonce(from) > ele.Nonce() {
return pool.ErrNonceTooLow
}
}
return nil
}
func (h *TxHelper) Sender(ele pool.Element) (common.Address, error) {
tx := (ele).(*types.Transaction)
return h.signer.Sender(tx)
}
func NewTxPool(conf *config.Config, c *chain.BlockChain) pool.Pool {
s := types.MakeSigner(conf.ChainConfig.TxSignerType, conf.ChainConfig.ChainID)
helper := &TxHelper{
signer: s,
}
if conf.TxPoolConfig.FakeMode {
return pool.NewFakePool(conf.TxPoolConfig.StartCleanTime, conf.TxPoolConfig.CleanPeriod, conf.TxPoolConfig.LeftEleNumEachAddr, helper)
}
return pool.NewPool(*conf.TxPoolConfig, c, TransactionType, helper)
}
func ElemsToTxs(elems []pool.Element) []*types.Transaction {
if len(elems) == 0 {
return make([]*types.Transaction, 0)
}
if !IsTx(elems[0]) {
log.Error("the element type is not *types.Transaction.", "element", elems[0]) // should never happen.
return nil
}
txs := make([]*types.Transaction, len(elems))
for i, elem := range elems {
txs[i] = elem.(*types.Transaction)
}
return txs
}
func IsTx(elem pool.Element) bool {
_, ok := elem.(*types.Transaction)
return ok
}