From daa4481282c26a1727a177c923e07ac96108310c Mon Sep 17 00:00:00 2001 From: Evgeny Khirin <32414982+evgeny-khirin@users.noreply.github.com> Date: Sun, 21 Apr 2019 15:05:03 +0300 Subject: [PATCH] [NOD-66] Transaction generator (#247) * [NOD-66] Created TX generator * [NOD-66] Created transaction generator * [NOD-66] Improved TX generator against double spend. Created genaddr utility. Refactored * [NOD-66] Save chenges before branch switch * [NOD-66] Use log package instead of fmt * [NOD-66] Fixed/restored docker files * [NOD-66] Changed according to new WithLock/NoLock convention --- blockdag/dag.go | 10 +- blockdag/dag_test.go | 2 +- cmd/genaddr/genaddr.go | 29 ++++ cmd/txgen/addresslist.go | 22 +++ cmd/txgen/config.go | 34 ++++ cmd/txgen/connect.go | 47 ++++++ cmd/txgen/docker/Dockerfile | 33 ++++ cmd/txgen/docker/README | 9 + cmd/txgen/main.go | 85 ++++++++++ cmd/txgen/txloop.go | 320 ++++++++++++++++++++++++++++++++++++ mempool/mempool.go | 6 +- mempool/mempool_test.go | 16 +- mining/mining.go | 4 +- server/p2p/p2p.go | 4 +- 14 files changed, 602 insertions(+), 19 deletions(-) create mode 100644 cmd/genaddr/genaddr.go create mode 100644 cmd/txgen/addresslist.go create mode 100644 cmd/txgen/config.go create mode 100644 cmd/txgen/connect.go create mode 100644 cmd/txgen/docker/Dockerfile create mode 100644 cmd/txgen/docker/README create mode 100644 cmd/txgen/main.go create mode 100644 cmd/txgen/txloop.go diff --git a/blockdag/dag.go b/blockdag/dag.go index 36857ac82..5962f069a 100644 --- a/blockdag/dag.go +++ b/blockdag/dag.go @@ -346,12 +346,18 @@ type SequenceLock struct { // // This function is safe for concurrent access. func (dag *BlockDAG) CalcSequenceLock(tx *util.Tx, utxoSet UTXOSet, mempool bool) (*SequenceLock, error) { - dag.dagLock.Lock() - defer dag.dagLock.Unlock() + dag.dagLock.RLock() + defer dag.dagLock.RUnlock() return dag.calcSequenceLock(dag.selectedTip(), utxoSet, tx, mempool) } +// CalcSequenceLockNoLock is lock free version of CalcSequenceLockWithLock +// This function is unsafe for concurrent access. +func (dag *BlockDAG) CalcSequenceLockNoLock(tx *util.Tx, utxoSet UTXOSet, mempool bool) (*SequenceLock, error) { + return dag.calcSequenceLock(dag.selectedTip(), utxoSet, tx, mempool) +} + // calcSequenceLock computes the relative lock-times for the passed // transaction. See the exported version, CalcSequenceLock for further details. // diff --git a/blockdag/dag_test.go b/blockdag/dag_test.go index a9492c601..fd5928d7e 100644 --- a/blockdag/dag_test.go +++ b/blockdag/dag_test.go @@ -219,7 +219,7 @@ func TestHaveBlock(t *testing.T) { } // TestCalcSequenceLock tests the LockTimeToSequence function, and the -// CalcSequenceLock method of a Chain instance. The tests exercise several +// CalcSequenceLock method of a DAG instance. The tests exercise several // combinations of inputs to the CalcSequenceLock function in order to ensure // the returned SequenceLocks are correct for each test instance. func TestCalcSequenceLock(t *testing.T) { diff --git a/cmd/genaddr/genaddr.go b/cmd/genaddr/genaddr.go new file mode 100644 index 000000000..b5ed03f39 --- /dev/null +++ b/cmd/genaddr/genaddr.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "os" + + "github.com/daglabs/btcd/btcec" + "github.com/daglabs/btcd/dagconfig" + "github.com/daglabs/btcd/util" + "github.com/daglabs/btcd/util/base58" +) + +func main() { + activeNetParams := &dagconfig.DevNetParams + privateKey, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate private key: %s", err) + os.Exit(1) + } + fmt.Printf("\nPrivate key (base-58): %s\n", base58.Encode(privateKey.Serialize())) + serializedKey := privateKey.PubKey().SerializeCompressed() + pubKeyAddr, err := util.NewAddressPubKey(serializedKey, activeNetParams.Prefix) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to generate public key address: %s", err) + os.Exit(1) + } + addr := pubKeyAddr.AddressPubKeyHash() + fmt.Printf("Public key: %s\n\n", addr) +} diff --git a/cmd/txgen/addresslist.go b/cmd/txgen/addresslist.go new file mode 100644 index 000000000..e71744b4f --- /dev/null +++ b/cmd/txgen/addresslist.go @@ -0,0 +1,22 @@ +package main + +import ( + "bufio" + "os" +) + +func getAddressList(cfg *config) ([]string, error) { + file, err := os.Open(cfg.AddressListPath) + if err != nil { + return nil, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + addressList := []string{} + for scanner.Scan() { + addressList = append(addressList, scanner.Text()) + } + + return addressList, nil +} diff --git a/cmd/txgen/config.go b/cmd/txgen/config.go new file mode 100644 index 000000000..da984bfc1 --- /dev/null +++ b/cmd/txgen/config.go @@ -0,0 +1,34 @@ +package main + +import ( + "errors" + + "github.com/jessevdk/go-flags" +) + +type config struct { + AddressListPath string `long:"addresslist" description:"Path to a list of nodes' JSON-RPC endpoints" required:"true"` + PrivateKey string `long:"private-key" description:"Private key" required:"true"` + CertificatePath string `long:"cert" description:"Path to certificate accepted by JSON-RPC endpoint"` + DisableTLS bool `long:"notls" description:"Disable TLS"` +} + +func parseConfig() (*config, error) { + cfg := &config{} + parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag) + _, err := parser.Parse() + + if err != nil { + return nil, err + } + + if cfg.CertificatePath == "" && !cfg.DisableTLS { + return nil, errors.New("--notls has to be disabled if --cert is used") + } + + if cfg.CertificatePath != "" && cfg.DisableTLS { + return nil, errors.New("--cert should be omitted if --notls is used") + } + + return cfg, nil +} diff --git a/cmd/txgen/connect.go b/cmd/txgen/connect.go new file mode 100644 index 000000000..3c6b196a4 --- /dev/null +++ b/cmd/txgen/connect.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + + "github.com/daglabs/btcd/rpcclient" +) + +func connectToServers(cfg *config, addressList []string) ([]*rpcclient.Client, error) { + clients := make([]*rpcclient.Client, len(addressList)) + + var cert []byte + if !cfg.DisableTLS { + var err error + cert, err = ioutil.ReadFile(cfg.CertificatePath) + if err != nil { + return nil, fmt.Errorf("Error reading certificates file: %s", err) + } + } + + for i, address := range addressList { + connCfg := &rpcclient.ConnConfig{ + Host: address, + Endpoint: "ws", + User: "user", + Pass: "pass", + DisableTLS: cfg.DisableTLS, + } + + if !cfg.DisableTLS { + connCfg.Certificates = cert + } + + client, err := rpcclient.New(connCfg, nil) + if err != nil { + return nil, fmt.Errorf("Error connecting to address %s: %s", address, err) + } + + clients[i] = client + + log.Printf("Connected to server %s", address) + } + + return clients, nil +} diff --git a/cmd/txgen/docker/Dockerfile b/cmd/txgen/docker/Dockerfile new file mode 100644 index 000000000..3bf08e249 --- /dev/null +++ b/cmd/txgen/docker/Dockerfile @@ -0,0 +1,33 @@ +# -- multistage docker build: stage #1: build stage +FROM golang:1.12-alpine AS build + +RUN mkdir -p /go/src/github.com/daglabs/btcd + +WORKDIR /go/src/github.com/daglabs/btcd + +RUN apk add --no-cache curl git + +# GO111MODULE=on forces Go to use the go-module system +# TODO: remove this once Go 1.13 is released +ENV GO111MODULE=on + +COPY go.mod . +COPY go.sum . + +RUN go mod download + +COPY . . + +RUN cd cmd/txgen && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o txgen . + +# --- multistage docker build: stage #2: runtime image +FROM alpine +WORKDIR /app + +RUN apk add --no-cache tini + +COPY --from=build /go/src/github.com/daglabs/btcd/cmd/txgen/txgen /app/ + +ENTRYPOINT ["/sbin/tini", "--"] + +CMD ["/app/txgen"] diff --git a/cmd/txgen/docker/README b/cmd/txgen/docker/README new file mode 100644 index 000000000..b9d9c1885 --- /dev/null +++ b/cmd/txgen/docker/README @@ -0,0 +1,9 @@ +1. To build docker image invoke following command from btcd root directory: + docker build -t txgen -f ./cmd/txgen/docker/Dockerfile . + +2. To run: + a. create folder ~/.btcd/txgen with the following files: + rpc.cert - certificate file that all rpc nodes accept + addresses - list of node addresses in the format [hostname]:[port]. One node per line + b. run: + docker run -v ~/.btcd:/root/.btcd -t txgen diff --git a/cmd/txgen/main.go b/cmd/txgen/main.go new file mode 100644 index 000000000..147db6668 --- /dev/null +++ b/cmd/txgen/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "log" + "runtime/debug" + "sync/atomic" + + "github.com/daglabs/btcd/btcec" + "github.com/daglabs/btcd/dagconfig" + "github.com/daglabs/btcd/rpcclient" + "github.com/daglabs/btcd/signal" + "github.com/daglabs/btcd/util" + "github.com/daglabs/btcd/util/base58" +) + +var ( + isRunning int32 + activeNetParams *dagconfig.Params = &dagconfig.DevNetParams + p2pkhAddress util.Address + privateKey *btcec.PrivateKey +) + +// privateKeyToP2pkhAddress generates p2pkh address from private key. +func privateKeyToP2pkhAddress(key *btcec.PrivateKey, net *dagconfig.Params) (util.Address, error) { + serializedKey := key.PubKey().SerializeCompressed() + pubKeyAddr, err := util.NewAddressPubKey(serializedKey, net.Prefix) + if err != nil { + return nil, err + } + return pubKeyAddr.AddressPubKeyHash(), nil +} + +func main() { + defer handlePanic() + + cfg, err := parseConfig() + if err != nil { + log.Panicf("Error parsing command-line arguments: %s", err) + } + + privateKeyBytes := base58.Decode(cfg.PrivateKey) + privateKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), privateKeyBytes) + + p2pkhAddress, err = privateKeyToP2pkhAddress(privateKey, activeNetParams) + if err != nil { + log.Panicf("Failed to get P2PKH address from private key: %s", err) + } + + log.Printf("P2PKH address for private key: %s\n", p2pkhAddress) + + addressList, err := getAddressList(cfg) + if err != nil { + log.Panicf("Couldn't load address list: %s", err) + } + + clients, err := connectToServers(cfg, addressList) + if err != nil { + log.Panicf("Error connecting to servers: %s", err) + } + defer disconnect(clients) + + atomic.StoreInt32(&isRunning, 1) + + go txLoop(clients) + + interrupt := signal.InterruptListener() + <-interrupt + + atomic.StoreInt32(&isRunning, 0) +} + +func disconnect(clients []*rpcclient.Client) { + log.Printf("Disconnecting clients") + for _, client := range clients { + client.Disconnect() + } +} + +func handlePanic() { + err := recover() + if err != nil { + log.Printf("Fatal error: %s", err) + log.Printf("Stack trace: %s", debug.Stack()) + } +} diff --git a/cmd/txgen/txloop.go b/cmd/txgen/txloop.go new file mode 100644 index 000000000..8d314b9eb --- /dev/null +++ b/cmd/txgen/txloop.go @@ -0,0 +1,320 @@ +package main + +import ( + "bytes" + "encoding/hex" + "fmt" + "log" + "math/rand" + "sync/atomic" + "time" + + "github.com/daglabs/btcd/dagconfig/daghash" + "github.com/daglabs/btcd/mempool" + "github.com/daglabs/btcd/rpcclient" + "github.com/daglabs/btcd/txscript" + "github.com/daglabs/btcd/wire" +) + +// utxo represents an unspent output spendable by the memWallet. The maturity +// height of the transaction is recorded in order to properly observe the +// maturity period of direct coinbase outputs. +type utxo struct { + txOut *wire.TxOut + isLocked bool +} + +var ( + random = rand.New(rand.NewSource(time.Now().UnixNano())) + utxos map[wire.OutPoint]*utxo + pkScript []byte + spentTxs map[daghash.TxID]bool +) + +const ( + // Those constants should be updated, when monetary policy changed + minSpendableAmount uint64 = 10000 + minRelayTxFee uint64 = uint64(mempool.DefaultMinRelayTxFee) +) + +func isDust(value uint64) bool { + return value < minSpendableAmount+minRelayTxFee +} + +// evalOutputs evaluates each of the passed outputs, creating a new matching +// utxo within the wallet if we're able to spend the output. +func evalOutputs(outputs []*wire.TxOut, txID *daghash.TxID) { + for i, output := range outputs { + if isDust(output.Value) { + continue + } + op := wire.OutPoint{TxID: *txID, Index: uint32(i)} + utxos[op] = &utxo{txOut: output} + } +} + +// evalInputs scans all the passed inputs, deleting any utxos within the +// wallet which are spent by an input. +func evalInputs(inputs []*wire.TxIn) { + for _, txIn := range inputs { + op := txIn.PreviousOutPoint + if _, ok := utxos[op]; ok { + delete(utxos, op) + } + } +} + +func utxosFunds() uint64 { + var funds uint64 + for _, utxo := range utxos { + if utxo.isLocked { + continue + } + funds += utxo.txOut.Value + } + return funds +} + +func isTxMatured(tx *wire.MsgTx, confirmations uint64) bool { + if !tx.IsBlockReward() { + return confirmations >= 1 + } + return confirmations >= uint64(float64(activeNetParams.BlockRewardMaturity)*1.5) +} + +func fetchAndPopulateUtxos(client *rpcclient.Client) (funds uint64, exit bool, err error) { + skipCount := 0 + for atomic.LoadInt32(&isRunning) == 1 { + arr, err := client.SearchRawTransactionsVerbose(p2pkhAddress, skipCount, 1000, true, false, nil) + if err != nil { + log.Printf("No spandable transactions found and SearchRawTransactionsVerbose failed: %s", err) + funds := utxosFunds() + if !isDust(funds) { + // we have something to spend + log.Printf("We have enough funds to generate transactions: %d", funds) + return funds, false, nil + } + log.Printf("Sleeping 30 sec...") + for i := 0; i < 30; i++ { + time.Sleep(time.Second) + if atomic.LoadInt32(&isRunning) != 1 { + return 0, true, nil + } + } + skipCount = 0 + continue + } + receivedCount := len(arr) + skipCount += receivedCount + log.Printf("Received %d transactions", receivedCount) + for _, searchResult := range arr { + txBytes, err := hex.DecodeString(searchResult.Hex) + if err != nil { + log.Printf("Failed to decode transactions bytes: %s", err) + continue + } + txID, err := daghash.NewTxIDFromStr(searchResult.TxID) + if err != nil { + log.Printf("Failed to decode transaction ID: %s", err) + continue + } + var tx wire.MsgTx + rbuf := bytes.NewReader(txBytes) + err = tx.Deserialize(rbuf) + if err != nil { + log.Printf("Failed to deserialize transaction: %s", err) + continue + } + if spentTxs[*txID] { + continue + } + if isTxMatured(&tx, searchResult.Confirmations) { + spentTxs[*txID] = true + evalOutputs(tx.TxOut, txID) + evalInputs(tx.TxIn) + } + } + } + return 0, true, nil +} + +// fundTx attempts to fund a transaction sending amount bitcoin. The coins are +// selected such that the final amount spent pays enough fees as dictated by +// the passed fee rate. The passed fee rate should be expressed in +// satoshis-per-byte. +func fundTx(tx *wire.MsgTx, amount uint64, feeRate uint64) (uint64, error) { + const ( + // spendSize is the largest number of bytes of a sigScript + // which spends a p2pkh output: OP_DATA_73 OP_DATA_33 + spendSize = 1 + 73 + 1 + 33 + ) + + var ( + amountSelected uint64 + txSize int + ) + + for outPoint, utxo := range utxos { + if utxo.isLocked { + continue + } + + amountSelected += utxo.txOut.Value + + // Add the selected output to the transaction, updating the + // current tx size while accounting for the size of the future + // sigScript. + tx.AddTxIn(wire.NewTxIn(&outPoint, nil)) + txSize = tx.SerializeSize() + spendSize*len(tx.TxIn) + + // Calculate the fee required for the txn at this point + // observing the specified fee rate. If we don't have enough + // coins from he current amount selected to pay the fee, then + // continue to grab more coins. + reqFee := uint64(txSize) * feeRate + if amountSelected-reqFee < amount { + continue + } + + // If we have any change left over, then add an additional + // output to the transaction reserved for change. + changeVal := amountSelected - amount - reqFee + if changeVal > 0 { + changeOutput := &wire.TxOut{ + Value: changeVal, + PkScript: pkScript, + } + tx.AddTxOut(changeOutput) + } + + return reqFee, nil + } + + // If we've reached this point, then coin selection failed due to an + // insufficient amount of coins. + return 0, fmt.Errorf("not enough funds for coin selection") +} + +// signTxAndLockSpentUtxo signs new transaction and locks spentutxo +func signTxAndLockSpentUtxo(tx *wire.MsgTx) error { + // Populate all the selected inputs with valid sigScript for spending. + // Along the way record all outputs being spent in order to avoid a + // potential double spend. + spentOutputs := make([]*utxo, 0, len(tx.TxIn)) + for i, txIn := range tx.TxIn { + outPoint := txIn.PreviousOutPoint + utxo := utxos[outPoint] + txOut := utxo.txOut + + sigScript, err := txscript.SignatureScript(tx, i, txOut.PkScript, + txscript.SigHashAll, privateKey, true) + if err != nil { + log.Printf("Failed to sign transaction: %s", err) + return err + } + + txIn.SignatureScript = sigScript + + spentOutputs = append(spentOutputs, utxo) + } + + // As these outputs are now being spent by this newly created + // transaction, mark the outputs are "locked". This action ensures + // these outputs won't be double spent by any subsequent transactions. + // These locked outputs can be freed via a call to UnlockOutputs. + for _, utxo := range spentOutputs { + utxo.isLocked = true + } + + return nil +} + +// createTransaction returns a fully signed transaction paying to the specified +// outputs while observing the desired fee rate. The passed fee rate should be +// expressed in satoshis-per-byte. +func createTransaction(outputs []*wire.TxOut, feeRate uint64) (*wire.MsgTx, uint64, error) { + tx := wire.NewNativeMsgTx(wire.TxVersion, nil, nil) + + // Tally up the total amount to be sent in order to perform coin + // selection shortly below. + var outputAmount uint64 + for _, output := range outputs { + outputAmount += output.Value + tx.AddTxOut(output) + } + + // Attempt to fund the transaction with spendable utxos. + fees, err := fundTx(tx, outputAmount, feeRate) + if err != nil { + return nil, 0, err + } + + err = signTxAndLockSpentUtxo(tx) + if err != nil { + return nil, 0, err + } + + return tx, fees, nil +} + +// txLoop performs main loop of transaction generation +func txLoop(clients []*rpcclient.Client) { + clientsCount := int64(len(clients)) + + utxos = make(map[wire.OutPoint]*utxo) + spentTxs = make(map[daghash.TxID]bool) + + pkScript, err := txscript.PayToAddrScript(p2pkhAddress) + if err != nil { + log.Printf("Failed to generate pkscript to address: %s", err) + return + } + + for atomic.LoadInt32(&isRunning) == 1 { + funds, exit, err := fetchAndPopulateUtxos(clients[0]) + if exit { + return + } + if err != nil { + log.Printf("fetchAndPopulateUtxos failed: %s", err) + continue + } + + if isDust(funds) { + log.Printf("fetchAndPopulateUtxos returned not enough funds") + continue + } + + log.Printf("UTXO funds after population %d", funds) + + for !isDust(funds) { + amount := minSpendableAmount + uint64(random.Int63n(int64(minSpendableAmount*4))) + output := wire.NewTxOut(amount, pkScript) + + tx, fees, err := createTransaction([]*wire.TxOut{output}, 10) + + if err != nil { + log.Printf("Failed to create transaction (output value %d, funds %d): %s", + amount, funds, err) + continue + } + + log.Printf("Created transaction %s: amount %d, fees %d", tx.TxID(), amount, fees) + + funds = utxosFunds() + log.Printf("Remaining funds: %d", funds) + + var currentClient *rpcclient.Client + if clientsCount == 1 { + currentClient = clients[0] + } else { + currentClient = clients[random.Int63n(clientsCount)] + } + _, err = currentClient.SendRawTransaction(tx, true) + if err != nil { + log.Printf("Failed to send transaction: %s", err) + continue + } + } + } +} diff --git a/mempool/mempool.go b/mempool/mempool.go index 80ac698c7..b39981db0 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -73,10 +73,10 @@ type Config struct { // chain tip within the best chain. MedianTimePast func() time.Time - // CalcSequenceLock defines the function to use in order to generate + // CalcSequenceLockNoLock defines the function to use in order to generate // the current sequence lock for the given transaction using the passed // utxo set. - CalcSequenceLock func(*util.Tx, blockdag.UTXOSet) (*blockdag.SequenceLock, error) + CalcSequenceLockNoLock func(*util.Tx, blockdag.UTXOSet) (*blockdag.SequenceLock, error) // IsDeploymentActive returns true if the target deploymentID is // active, and false otherwise. The mempool uses this function to gauge @@ -852,7 +852,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rateLimit, rejectDu // Don't allow the transaction into the mempool unless its sequence // lock is active, meaning that it'll be allowed into the next block // with respect to its defined relative lock times. - sequenceLock, err := mp.cfg.CalcSequenceLock(tx, mp.mpUTXOSet) + sequenceLock, err := mp.cfg.CalcSequenceLockNoLock(tx, mp.mpUTXOSet) if err != nil { if cerr, ok := err.(blockdag.RuleError); ok { return nil, nil, dagRuleError(cerr) diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index f5f1764ae..db647cb1b 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -319,12 +319,12 @@ func newPoolHarness(dagParams *dagconfig.Params, numOutputs uint32, dbName strin MinRelayTxFee: 1000, // 1 Satoshi per byte MaxTxVersion: 1, }, - DAGParams: dagParams, - BestHeight: chain.BestHeight, - MedianTimePast: chain.MedianTimePast, - CalcSequenceLock: calcSequenceLock, - SigCache: nil, - AddrIndex: nil, + DAGParams: dagParams, + BestHeight: chain.BestHeight, + MedianTimePast: chain.MedianTimePast, + CalcSequenceLockNoLock: calcSequenceLock, + SigCache: nil, + AddrIndex: nil, }), } @@ -681,7 +681,7 @@ func TestProcessTransaction(t *testing.T) { } //Checks that transactions get rejected from mempool if sequence lock is not active - harness.txPool.cfg.CalcSequenceLock = func(tx *util.Tx, + harness.txPool.cfg.CalcSequenceLockNoLock = func(tx *util.Tx, view blockdag.UTXOSet) (*blockdag.SequenceLock, error) { return &blockdag.SequenceLock{ @@ -704,7 +704,7 @@ func TestProcessTransaction(t *testing.T) { if err.Error() != expectedErrStr { t.Errorf("Unexpected error message. Expected \"%s\" but got \"%s\"", expectedErrStr, err.Error()) } - harness.txPool.cfg.CalcSequenceLock = calcSequenceLock + harness.txPool.cfg.CalcSequenceLockNoLock = calcSequenceLock // This is done in order to increase the input age, so the tx priority will be higher harness.chain.SetHeight(curHeight + 100) diff --git a/mining/mining.go b/mining/mining.go index 088ca37ac..a4244d1d8 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -406,8 +406,7 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe if err != nil { return nil, err } - coinbaseTx, err := CreateCoinbaseTx(g.dagParams, coinbaseScript, - nextBlockHeight, payToAddress) + coinbaseTx, err := CreateCoinbaseTx(g.dagParams, coinbaseScript, nextBlockHeight, payToAddress) if err != nil { return nil, err } @@ -630,7 +629,6 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe // the total fees accordingly. blockSize -= wire.MaxVarIntPayload - uint32(wire.VarIntSerializeSize(uint64(len(blockTxns)))) - coinbaseTx.MsgTx().TxOut[0].Value += totalFees // Calculate the required difficulty for the block. The timestamp // is potentially adjusted to ensure it comes after the median time of diff --git a/server/p2p/p2p.go b/server/p2p/p2p.go index ee9518759..f90087704 100644 --- a/server/p2p/p2p.go +++ b/server/p2p/p2p.go @@ -2476,8 +2476,8 @@ func NewServer(listenAddrs []string, db database.DB, dagParams *dagconfig.Params DAGParams: dagParams, BestHeight: func() int32 { return s.DAG.Height() }, //TODO: (Ori) This is probably wrong. Done only for compilation MedianTimePast: func() time.Time { return s.DAG.CalcPastMedianTime() }, - CalcSequenceLock: func(tx *util.Tx, utxoSet blockdag.UTXOSet) (*blockdag.SequenceLock, error) { - return s.DAG.CalcSequenceLock(tx, utxoSet, true) + CalcSequenceLockNoLock: func(tx *util.Tx, utxoSet blockdag.UTXOSet) (*blockdag.SequenceLock, error) { + return s.DAG.CalcSequenceLockNoLock(tx, utxoSet, true) }, IsDeploymentActive: s.DAG.IsDeploymentActive, SigCache: s.SigCache,