Skip to content

Commit be1d867

Browse files
committed
[refactor] call ltx.AcceptTxToMemPool for detail tx checks, during disconnectTip and sendrawtransaction.
1 parent f80b7bd commit be1d867

File tree

8 files changed

+123
-150
lines changed

8 files changed

+123
-150
lines changed

errcode/txerror.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@ import "fmt"
55
type TxErr int
66

77
const (
8-
TxErrRejectNonstandard TxErr = 0x40
9-
TxErrRejectDust TxErr = 0x41
108
TxErrRejectCheckPoint TxErr = 0x43
119

12-
TxErrRejectAlreadyKnown TxErr = 0x101
13-
TxErrRejectConflict TxErr = 0x102
14-
1510
TxErrNoPreviousOut TxErr = TxErrorBase + iota
1611
ScriptCheckInputsBug
1712
TxErrSignRawTransaction
@@ -20,11 +15,7 @@ const (
2015
)
2116

2217
var txErrorToString = map[TxErr]string{
23-
TxErrRejectNonstandard: "TxErrRejectNonstandard",
24-
TxErrRejectDust: "TxErrRejectDust",
2518
TxErrRejectCheckPoint: "TxErrRejectCheckPoint",
26-
TxErrRejectAlreadyKnown: "TxErrRejectAlreadyKnown",
27-
TxErrRejectConflict: "TxErrRejectConflict",
2819
TxErrNoPreviousOut: "There is no previousout",
2920
ScriptCheckInputsBug: "ScriptCheckInputsBug",
3021
TxErrSignRawTransaction: "TxErrSignRawTransaction",

errcode/txerror_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@ func TestTxErr_String(t *testing.T) {
99
in TxErr
1010
want string
1111
}{
12-
{TxErrRejectNonstandard, "TxErrRejectNonstandard"},
13-
{TxErrRejectDust, "TxErrRejectDust"},
1412
{TxErrRejectCheckPoint, "TxErrRejectCheckPoint"},
15-
{TxErrRejectAlreadyKnown, "TxErrRejectAlreadyKnown"},
16-
{TxErrRejectConflict, "TxErrRejectConflict"},
1713
{TxErrNoPreviousOut, "There is no previousout"},
1814
{ScriptCheckInputsBug, "ScriptCheckInputsBug"},
1915
{TxErrSignRawTransaction, "TxErrSignRawTransaction"},

logic/lmempool/ltxmempool.go

Lines changed: 18 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,31 @@ import (
1818
"github.com/copernet/copernicus/util"
1919
)
2020

21-
// AcceptTxToMemPool add one check corret transaction to mempool.
22-
func AcceptTxToMemPool(tx *tx.Tx) error {
21+
func AcceptTxToMemPool(txn *tx.Tx) error {
22+
txEntry, err := ltx.CheckTxBeforeAcceptToMemPool(txn)
23+
if err != nil {
24+
return err
25+
}
2326

24-
//first : check whether enter mempool.
27+
return addTxToMemPool(txEntry)
28+
}
29+
30+
func addTxToMemPool(txe *mempool.TxEntry) error {
2531
pool := mempool.GetInstance()
26-
pool.Lock()
27-
defer pool.Unlock()
2832

29-
gChain := chain.GetInstance()
30-
utxoTip := utxo.GetUtxoCacheInstance()
31-
32-
allPreout := tx.GetAllPreviousOut()
33-
coins := make([]*utxo.Coin, len(allPreout))
34-
var txfee int64
35-
var inputValue int64
36-
spendCoinbase := false
37-
38-
for i, preout := range allPreout {
39-
if coin := utxoTip.GetCoin(&preout); coin != nil {
40-
coins[i] = coin
41-
inputValue += int64(coin.GetAmount())
42-
if coin.IsCoinBase() {
43-
spendCoinbase = true
44-
}
45-
} else {
46-
if coin := pool.GetCoin(&preout); coin != nil {
47-
coins[i] = coin
48-
inputValue += int64(coin.GetAmount())
49-
if coin.IsCoinBase() {
50-
spendCoinbase = true
51-
}
52-
} else {
53-
log.Error("the transaction in mempool, not found its parent " +
54-
"transaction in local node and utxo")
55-
return errcode.New(errcode.TxErrNoPreviousOut)
56-
}
57-
}
58-
}
33+
ancestorNum := conf.Cfg.Mempool.LimitAncestorCount
34+
ancestorSize := conf.Cfg.Mempool.LimitAncestorSize
35+
descendantNum := conf.Cfg.Mempool.LimitDescendantCount
36+
descendantSize := conf.Cfg.Mempool.LimitDescendantSize
37+
38+
ancestors, err := pool.CalculateMemPoolAncestors(txe.Tx, uint64(ancestorNum), uint64(ancestorSize*1000),
39+
uint64(descendantNum), uint64(descendantSize*1000), true)
5940

60-
txfee = inputValue - int64(tx.GetValueOut())
61-
ancestors, lp, err := isTxAcceptable(tx, txfee)
6241
if err != nil {
6342
return err
6443
}
6544

66-
//TODO: sigsCount := ltx.GetTransactionSigOpCount(tx, script.StandardScriptVerifyFlags,
67-
68-
//second : add transaction to mempool.
69-
txentry := mempool.NewTxentry(tx, txfee, util.GetTime(), gChain.Height(), *lp,
70-
tx.GetSigOpCountWithoutP2SH(), spendCoinbase)
71-
72-
pool.AddTx(txentry, ancestors)
73-
45+
pool.AddTx(txe, ancestors)
7446
return nil
7547
}
7648

@@ -95,7 +67,7 @@ func TryAcceptOrphansTxs(transaction *tx.Tx) (acceptTxs []*tx.Tx, rejectTxs []ut
9567
continue
9668
}
9769

98-
err := AcceptTxToMemPool(iOrphanTx.Tx) //TODO: check transaction before add to mempool
70+
err := AcceptTxToMemPool(iOrphanTx.Tx)
9971
if err == nil {
10072
acceptTxs = append(acceptTxs, iOrphanTx.Tx)
10173
for i := 0; i < iOrphanTx.Tx.GetOutsCount(); i++ {
@@ -120,52 +92,11 @@ func TryAcceptOrphansTxs(transaction *tx.Tx) (acceptTxs []*tx.Tx, rejectTxs []ut
12092
return
12193
}
12294

123-
func isTxAcceptable(tx *tx.Tx, txfee int64) (map[*mempool.TxEntry]struct{}, *mempool.LockPoints, error) {
124-
pool := mempool.GetInstance()
125-
allEntry := pool.GetAllTxEntryWithoutLock()
126-
if _, ok := allEntry[tx.GetHash()]; ok {
127-
return nil, nil, errcode.New(errcode.AlreadHaveTx)
128-
}
129-
130-
lp := ltx.CalculateLockPoints(tx, consensus.LocktimeVerifySequence|consensus.LocktimeMedianTimePast)
131-
if lp == nil {
132-
return nil, lp, errcode.New(errcode.Nomature)
133-
}
134-
if !ltx.CheckSequenceLocks(lp.Height, lp.Time) {
135-
return nil, lp, errcode.New(errcode.Nomature)
136-
}
137-
138-
ancestorNum := conf.Cfg.Mempool.LimitAncestorCount
139-
ancestorSize := conf.Cfg.Mempool.LimitAncestorSize
140-
descendantNum := conf.Cfg.Mempool.LimitDescendantCount
141-
descendantSize := conf.Cfg.Mempool.LimitDescendantSize
142-
ancestors, err := pool.CalculateMemPoolAncestors(tx, uint64(ancestorNum), uint64(ancestorSize*1000),
143-
uint64(descendantNum), uint64(descendantSize*1000), true)
144-
if err != nil {
145-
return nil, lp, err
146-
}
147-
148-
txsize := int64(tx.EncodeSize())
149-
minfeeRate := pool.GetMinFee(conf.Cfg.Mempool.MaxPoolSize)
150-
rejectFee := minfeeRate.GetFee(int(txsize))
151-
// compare the transaction feeRate with enter mempool min txfeeRate
152-
if txfee < rejectFee {
153-
return nil, lp, errcode.New(errcode.RejectInsufficientFee)
154-
}
155-
156-
return ancestors, lp, nil
157-
}
158-
15995
func RemoveTxSelf(txs []*tx.Tx) {
16096
pool := mempool.GetInstance()
16197
pool.RemoveTxSelf(txs)
16298
}
16399

164-
func RemoveTxRecursive(origTx *tx.Tx, reason mempool.PoolRemovalReason) {
165-
pool := mempool.GetInstance()
166-
pool.RemoveTxRecursive(origTx, reason)
167-
}
168-
169100
func RemoveForReorg(nMemPoolHeight int32, flag int) {
170101
//gChain := chain.GetInstance()
171102
view := utxo.GetUtxoCacheInstance()

logic/lreindex/lreindex.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func Reindex() (err error) {
2323
blkFiles, err := disk.GetBlkFiles()
2424
if err != nil {
2525
log.Error("reindex: get blk files failed, err:%s", err)
26+
return err
2627
}
2728

2829
log.Info("Start reindexing")

logic/ltx/ltx.go

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ltx
22

33
import (
44
"bytes"
5+
"fmt"
56
"github.com/copernet/copernicus/logic/lscript"
67
"github.com/copernet/copernicus/model/tx"
78
"github.com/copernet/copernicus/model/utxo"
@@ -65,54 +66,49 @@ func ScriptVerifyInit() {
6566
}
6667
}
6768

68-
// CheckRegularTransaction transaction service will use this func to check transaction before accepting to mempool
69-
func CheckRegularTransaction(txn *tx.Tx) error {
69+
func CheckTxBeforeAcceptToMemPool(txn *tx.Tx) (*mempool.TxEntry, error) {
7070
if err := txn.CheckRegularTransaction(); err != nil {
71-
return err
71+
return nil, err
7272
}
7373

7474
if model.ActiveNetParams.RequireStandard {
7575
ok, reason := txn.IsStandard()
7676
if !ok {
7777
log.Debug("non standard tx: %s, reason: %s", txn.GetHash(), reason)
78-
return errcode.NewError(errcode.RejectNonstandard, reason)
78+
return nil, errcode.NewError(errcode.RejectNonstandard, reason)
7979
}
8080
}
8181

8282
// check common locktime, sequence final can disable it
8383
err := ContextualCheckTransactionForCurrentBlock(txn, int(tx.StandardLockTimeVerifyFlags))
8484
if err != nil {
85-
return errcode.New(errcode.RejectNonstandard)
85+
return nil, errcode.New(errcode.RejectNonstandard)
8686
}
8787

8888
// is mempool already have it? conflict tx with mempool
8989
gPool := mempool.GetInstance()
9090
if gPool.FindTx(txn.GetHash()) != nil {
9191
log.Debug("tx already known in mempool, hash: %s", txn.GetHash())
92-
return errcode.NewError(errcode.RejectAlreadyKnown, "txn-already-in-mempool")
92+
return nil, errcode.NewError(errcode.RejectAlreadyKnown, "txn-already-in-mempool")
9393
}
9494

9595
for _, txin := range txn.GetIns() {
9696
if gPool.HasSpentOut(txin.PreviousOutPoint) {
9797
log.Debug("tx ins alread spent out in mempool, tx hash:%s", txn.GetHash())
98-
return errcode.NewError(errcode.TxErrRejectConflict, "txn-mempool-conflict")
98+
return nil, errcode.NewError(errcode.RejectConflict, "txn-mempool-conflict")
9999
}
100100
}
101101

102102
// check outpoint alread exist
103103
if areOutputsAlreadExist(txn) {
104104
log.Debug("tx's outpoint already known in utxo, tx hash: %s", txn.GetHash())
105-
return errcode.NewError(errcode.TxErrRejectAlreadyKnown, "txn-already-known")
105+
return nil, errcode.NewError(errcode.RejectAlreadyKnown, "txn-already-known")
106106
}
107107

108108
// are inputs are exists and available?
109-
inputCoins, missingInput, alreadySpent := inputCoinsOf(txn)
109+
inputCoins, missingInput, spendCoinbase := inputCoinsOf(txn)
110110
if missingInput {
111-
return errcode.New(errcode.TxErrNoPreviousOut)
112-
}
113-
114-
if alreadySpent {
115-
return errcode.NewError(errcode.RejectDuplicate, "bad-txns-inputs-spent")
111+
return nil, errcode.New(errcode.TxErrNoPreviousOut)
116112
}
117113

118114
// CLTV(CheckLockTimeVerify)
@@ -124,7 +120,7 @@ func CheckRegularTransaction(txn *tx.Tx) error {
124120
lp := CalculateLockPoints(txn, uint32(tx.StandardLockTimeVerifyFlags))
125121
if lp == nil {
126122
log.Debug("cann't calculate out lockpoints")
127-
return errcode.New(errcode.RejectNonstandard)
123+
return nil, errcode.New(errcode.RejectNonstandard)
128124
}
129125
// Only accept BIP68 sequence locked transactions that can be mined
130126
// in the next block; we don't want our mempool filled up with
@@ -133,13 +129,13 @@ func CheckRegularTransaction(txn *tx.Tx) error {
133129
// instead of create its own.
134130
if !CheckSequenceLocks(lp.Height, lp.Time) {
135131
log.Debug("tx sequence lock check faild")
136-
return errcode.NewError(errcode.RejectNonstandard, "non-BIP68-final")
132+
return nil, errcode.NewError(errcode.RejectNonstandard, "non-BIP68-final")
137133
}
138134

139135
//check standard inputs
140136
if model.ActiveNetParams.RequireStandard {
141137
if areInputsStandard(txn, inputCoins) {
142-
return errcode.NewError(errcode.RejectNonstandard, "bad-txns-nonstandard-inputs")
138+
return nil, errcode.NewError(errcode.RejectNonstandard, "bad-txns-nonstandard-inputs")
143139
}
144140
}
145141

@@ -150,9 +146,18 @@ func CheckRegularTransaction(txn *tx.Tx) error {
150146
// than merely non-standard transaction.
151147
sigOpsCount := GetTransactionSigOpCount(txn, uint32(script.StandardScriptVerifyFlags), inputCoins)
152148
if uint(sigOpsCount) > tx.MaxStandardTxSigOps {
153-
return errcode.NewError(errcode.RejectNonstandard, "bad-txns-too-many-sigops")
149+
return nil, errcode.NewError(errcode.RejectNonstandard, "bad-txns-too-many-sigops")
150+
}
151+
152+
txFee, err := checkFee(txn, inputCoins)
153+
if err != nil {
154+
return nil, err
154155
}
155156

157+
//TODO: Require that free transactions have sufficient priority to be mined in the next block
158+
//TODO: Continuously rate-limit free (really, very-low-fee) transactions.
159+
//TODO: check absurdly-high-fee (nFees > nAbsurdFee)
160+
156161
var extraFlags uint32 = script.ScriptVerifyNone
157162
tip := chain.GetInstance().Tip()
158163
//if chainparams.IsMagneticAnomalyEnable(tip.GetMedianTimePast()) {
@@ -177,7 +182,7 @@ func CheckRegularTransaction(txn *tx.Tx) error {
177182
// prevent CPU exhaustion denial-of-service attacks.
178183
err = checkInputs(txn, inputCoins, scriptVerifyFlags)
179184
if err != nil {
180-
return err
185+
return nil, err
181186
}
182187

183188
// Check again against the current block tip's script verification flags
@@ -199,18 +204,38 @@ func CheckRegularTransaction(txn *tx.Tx) error {
199204
err = checkInputs(txn, inputCoins, currentBlockScriptVerifyFlags)
200205
if err != nil {
201206
if ((^scriptVerifyFlags) & currentBlockScriptVerifyFlags) == 0 {
202-
return errcode.New(errcode.ScriptCheckInputsBug)
207+
return nil, errcode.New(errcode.ScriptCheckInputsBug)
203208
}
204209
err = checkInputs(txn, inputCoins, uint32(script.MandatoryScriptVerifyFlags)|extraFlags)
205210
if err != nil {
206-
return err
211+
return nil, err
207212
}
208213

209214
log.Debug("Warning: -promiscuousmempool flags set to not include currently enforced soft forks, " +
210215
"this may break mining or otherwise cause instability!\n")
211216
}
212217

213-
return nil
218+
txEntry := mempool.NewTxentry(txn, txFee, util.GetTime(),
219+
chain.GetInstance().Height(), *lp, sigOpsCount, spendCoinbase)
220+
221+
return txEntry, nil
222+
}
223+
224+
func checkFee(txn *tx.Tx, inputCoins *utxo.CoinsMap) (int64, error) {
225+
inputValue := inputCoins.GetValueIn(txn)
226+
txFee := inputValue - txn.GetValueOut()
227+
228+
txsize := int64(txn.EncodeSize())
229+
minfeeRate := mempool.GetInstance().GetMinFee(conf.Cfg.Mempool.MaxPoolSize)
230+
rejectFee := minfeeRate.GetFee(int(txsize))
231+
232+
if int64(txFee) < rejectFee {
233+
reason := fmt.Sprintf("mempool min fee not met %d < %d", txFee, rejectFee)
234+
log.Debug("reject tx:%s, for %s", txn.GetHash(), reason)
235+
return 0, errcode.NewError(errcode.RejectInsufficientFee, reason)
236+
}
237+
238+
return int64(txFee), nil
214239
}
215240

216241
func promiscuousMempoolFlags() uint32 {
@@ -328,7 +353,7 @@ func ApplyBlockTransactions(txs []*tx.Tx, bip30Enable bool, scriptCheckFlags uin
328353
coinHeight, coinTime := CalculateSequenceLocks(transaction, coinsMap, scriptCheckFlags)
329354
if !CheckSequenceLocks(coinHeight, coinTime) {
330355
log.Debug("block contains a non-bip68-final transaction")
331-
return nil, nil, errcode.New(errcode.TxErrRejectNonstandard)
356+
return nil, nil, errcode.New(errcode.RejectNonstandard)
332357
}
333358
}
334359
//check sigops
@@ -434,7 +459,7 @@ func areOutputsAlreadExist(transaction *tx.Tx) (exist bool) {
434459
return false
435460
}
436461

437-
func inputCoinsOf(txn *tx.Tx) (coinMap *utxo.CoinsMap, missingInput, alreadySpent bool) {
462+
func inputCoinsOf(txn *tx.Tx) (coinMap *utxo.CoinsMap, missingInput bool, spendCoinbase bool) {
438463
coinMap = utxo.NewEmptyCoinsMap()
439464

440465
for _, txin := range txn.GetIns() {
@@ -445,18 +470,18 @@ func inputCoinsOf(txn *tx.Tx) (coinMap *utxo.CoinsMap, missingInput, alreadySpen
445470
coin = mempool.GetInstance().GetCoin(prevout)
446471
}
447472

448-
if coin == nil {
449-
return nil, true, false
473+
if coin == nil || coin.IsSpent() {
474+
return coinMap, true, spendCoinbase
450475
}
451476

452-
if coin.IsSpent() {
453-
return nil, false, true
477+
if coin.IsCoinBase() {
478+
spendCoinbase = true
454479
}
455480

456481
coinMap.AddCoin(prevout, coin, coin.IsCoinBase())
457482
}
458483

459-
return coinMap, false, false
484+
return coinMap, false, spendCoinbase
460485
}
461486

462487
func GetTransactionSigOpCount(txn *tx.Tx, flags uint32, coinMap *utxo.CoinsMap) int {

0 commit comments

Comments
 (0)