@@ -2,6 +2,7 @@ package ltx
2
2
3
3
import (
4
4
"bytes"
5
+ "fmt"
5
6
"github.com/copernet/copernicus/logic/lscript"
6
7
"github.com/copernet/copernicus/model/tx"
7
8
"github.com/copernet/copernicus/model/utxo"
@@ -65,54 +66,49 @@ func ScriptVerifyInit() {
65
66
}
66
67
}
67
68
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 ) {
70
70
if err := txn .CheckRegularTransaction (); err != nil {
71
- return err
71
+ return nil , err
72
72
}
73
73
74
74
if model .ActiveNetParams .RequireStandard {
75
75
ok , reason := txn .IsStandard ()
76
76
if ! ok {
77
77
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 )
79
79
}
80
80
}
81
81
82
82
// check common locktime, sequence final can disable it
83
83
err := ContextualCheckTransactionForCurrentBlock (txn , int (tx .StandardLockTimeVerifyFlags ))
84
84
if err != nil {
85
- return errcode .New (errcode .RejectNonstandard )
85
+ return nil , errcode .New (errcode .RejectNonstandard )
86
86
}
87
87
88
88
// is mempool already have it? conflict tx with mempool
89
89
gPool := mempool .GetInstance ()
90
90
if gPool .FindTx (txn .GetHash ()) != nil {
91
91
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" )
93
93
}
94
94
95
95
for _ , txin := range txn .GetIns () {
96
96
if gPool .HasSpentOut (txin .PreviousOutPoint ) {
97
97
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" )
99
99
}
100
100
}
101
101
102
102
// check outpoint alread exist
103
103
if areOutputsAlreadExist (txn ) {
104
104
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" )
106
106
}
107
107
108
108
// are inputs are exists and available?
109
- inputCoins , missingInput , alreadySpent := inputCoinsOf (txn )
109
+ inputCoins , missingInput , spendCoinbase := inputCoinsOf (txn )
110
110
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 )
116
112
}
117
113
118
114
// CLTV(CheckLockTimeVerify)
@@ -124,7 +120,7 @@ func CheckRegularTransaction(txn *tx.Tx) error {
124
120
lp := CalculateLockPoints (txn , uint32 (tx .StandardLockTimeVerifyFlags ))
125
121
if lp == nil {
126
122
log .Debug ("cann't calculate out lockpoints" )
127
- return errcode .New (errcode .RejectNonstandard )
123
+ return nil , errcode .New (errcode .RejectNonstandard )
128
124
}
129
125
// Only accept BIP68 sequence locked transactions that can be mined
130
126
// in the next block; we don't want our mempool filled up with
@@ -133,13 +129,13 @@ func CheckRegularTransaction(txn *tx.Tx) error {
133
129
// instead of create its own.
134
130
if ! CheckSequenceLocks (lp .Height , lp .Time ) {
135
131
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" )
137
133
}
138
134
139
135
//check standard inputs
140
136
if model .ActiveNetParams .RequireStandard {
141
137
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" )
143
139
}
144
140
}
145
141
@@ -150,9 +146,18 @@ func CheckRegularTransaction(txn *tx.Tx) error {
150
146
// than merely non-standard transaction.
151
147
sigOpsCount := GetTransactionSigOpCount (txn , uint32 (script .StandardScriptVerifyFlags ), inputCoins )
152
148
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
154
155
}
155
156
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
+
156
161
var extraFlags uint32 = script .ScriptVerifyNone
157
162
tip := chain .GetInstance ().Tip ()
158
163
//if chainparams.IsMagneticAnomalyEnable(tip.GetMedianTimePast()) {
@@ -177,7 +182,7 @@ func CheckRegularTransaction(txn *tx.Tx) error {
177
182
// prevent CPU exhaustion denial-of-service attacks.
178
183
err = checkInputs (txn , inputCoins , scriptVerifyFlags )
179
184
if err != nil {
180
- return err
185
+ return nil , err
181
186
}
182
187
183
188
// Check again against the current block tip's script verification flags
@@ -199,18 +204,38 @@ func CheckRegularTransaction(txn *tx.Tx) error {
199
204
err = checkInputs (txn , inputCoins , currentBlockScriptVerifyFlags )
200
205
if err != nil {
201
206
if ((^ scriptVerifyFlags ) & currentBlockScriptVerifyFlags ) == 0 {
202
- return errcode .New (errcode .ScriptCheckInputsBug )
207
+ return nil , errcode .New (errcode .ScriptCheckInputsBug )
203
208
}
204
209
err = checkInputs (txn , inputCoins , uint32 (script .MandatoryScriptVerifyFlags )| extraFlags )
205
210
if err != nil {
206
- return err
211
+ return nil , err
207
212
}
208
213
209
214
log .Debug ("Warning: -promiscuousmempool flags set to not include currently enforced soft forks, " +
210
215
"this may break mining or otherwise cause instability!\n " )
211
216
}
212
217
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
214
239
}
215
240
216
241
func promiscuousMempoolFlags () uint32 {
@@ -328,7 +353,7 @@ func ApplyBlockTransactions(txs []*tx.Tx, bip30Enable bool, scriptCheckFlags uin
328
353
coinHeight , coinTime := CalculateSequenceLocks (transaction , coinsMap , scriptCheckFlags )
329
354
if ! CheckSequenceLocks (coinHeight , coinTime ) {
330
355
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 )
332
357
}
333
358
}
334
359
//check sigops
@@ -434,7 +459,7 @@ func areOutputsAlreadExist(transaction *tx.Tx) (exist bool) {
434
459
return false
435
460
}
436
461
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 ) {
438
463
coinMap = utxo .NewEmptyCoinsMap ()
439
464
440
465
for _ , txin := range txn .GetIns () {
@@ -445,18 +470,18 @@ func inputCoinsOf(txn *tx.Tx) (coinMap *utxo.CoinsMap, missingInput, alreadySpen
445
470
coin = mempool .GetInstance ().GetCoin (prevout )
446
471
}
447
472
448
- if coin == nil {
449
- return nil , true , false
473
+ if coin == nil || coin . IsSpent () {
474
+ return coinMap , true , spendCoinbase
450
475
}
451
476
452
- if coin .IsSpent () {
453
- return nil , false , true
477
+ if coin .IsCoinBase () {
478
+ spendCoinbase = true
454
479
}
455
480
456
481
coinMap .AddCoin (prevout , coin , coin .IsCoinBase ())
457
482
}
458
483
459
- return coinMap , false , false
484
+ return coinMap , false , spendCoinbase
460
485
}
461
486
462
487
func GetTransactionSigOpCount (txn * tx.Tx , flags uint32 , coinMap * utxo.CoinsMap ) int {
0 commit comments