From 6106979d2c55d50ae951aa5bb95c1fb293e9bad8 Mon Sep 17 00:00:00 2001 From: JoeGruff Date: Thu, 23 Apr 2020 14:43:47 +0900 Subject: [PATCH 1/3] account: Use relayFee setting. Remove the realyFee method from dcrdata and have all relay fees passed in order to separate functions cleanly. Relay fees now depend upon the account calling the dcrdata method. --- decred/decred/dcr/account.py | 12 +++---- decred/decred/dcr/dcrdata.py | 34 +++++++------------ .../integration/dcr/test_dcrdata_live.py | 4 +-- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/decred/decred/dcr/account.py b/decred/decred/dcr/account.py index 58756251..ec65dbad 100644 --- a/decred/decred/dcr/account.py +++ b/decred/decred/dcr/account.py @@ -1865,7 +1865,7 @@ def addressSignal(self, addr, txid): # signal the balance update self.signals.balance(self.calcBalance()) - def sendToAddress(self, value, address, feeRate=None): + def sendToAddress(self, value, address): """ Send the value to the address. @@ -1880,7 +1880,7 @@ def sendToAddress(self, value, address, feeRate=None): priv=self.privKeyForAddress, internal=self.nextInternalAddress, ) tx, spentUTXOs, newUTXOs = self.blockchain.sendToAddress( - value, address, keysource, self.getUTXOs, feeRate + value, address, keysource, self.getUTXOs, self.relayFee ) self.addMempoolTx(tx) self.spendUTXOs(spentUTXOs) @@ -1907,13 +1907,13 @@ def purchaseTickets(self, qty, price): spendLimit=int(round(price * qty * 1.1 * 1e8)), # convert to atoms here poolAddress=pi.poolAddress, votingAddress=pi.ticketAddress, - ticketFee=0, # use network default + ticketFee=DefaultRelayFeePerKb, poolFees=pi.poolFees, count=qty, - txFee=0, # use network default + txFee=self.relayFee, ) txs, spentUTXOs, newUTXOs = self.blockchain.purchaseTickets( - keysource, self.getUTXOs, req + keysource, self.getUTXOs, req, self.relayFee ) # Add the split transactions self.addMempoolTx(txs[0]) @@ -1962,7 +1962,7 @@ def revokeTickets(self): priv=lambda _: self._votingKey, internal=lambda: "", ) - self.blockchain.revokeTicket(tx, keysource, redeemScript) + self.blockchain.revokeTicket(tx, keysource, redeemScript, self.relayFee) def sync(self): """ diff --git a/decred/decred/dcr/dcrdata.py b/decred/decred/dcr/dcrdata.py index a8cf41e0..f91c4ef4 100644 --- a/decred/decred/dcr/dcrdata.py +++ b/decred/decred/dcr/dcrdata.py @@ -841,15 +841,6 @@ def updateTip(self): log.error("failed to retrieve tip from blockchain: %s" % formatTraceback(e)) raise DecredError("no tip data retrieved") - def relayFee(self): - """ - Return the current transaction fee. - - Returns: - int: Atoms per kB of encoded transaction. - """ - return txscript.DefaultRelayFeePerKb - def saveBlockHeader(self, header): """ Save the block header to the database. @@ -861,7 +852,7 @@ def saveBlockHeader(self, header): self.heightMap[header.height] = bHash self.headerDB[bHash] = header - def sendToAddress(self, value, address, keysource, utxosource, feeRate=None): + def sendToAddress(self, value, address, keysource, utxosource, relayFee): """ Send the amount in atoms to the specified address. @@ -880,7 +871,7 @@ def sendToAddress(self, value, address, keysource, utxosource, feeRate=None): """ self.updateTip() outputs = makeOutputs([(address, value)], self.netParams) - return self.sendOutputs(outputs, keysource, utxosource, feeRate) + return self.sendOutputs(outputs, keysource, utxosource, relayFee) def broadcast(self, txHex): """ @@ -962,7 +953,7 @@ def confirmUTXO(self, utxo, block=None, tx=None): pass return False - def sendOutputs(self, outputs, keysource, utxosource, feeRate=None): + def sendOutputs(self, outputs, keysource, utxosource, relayFee): """ Send the `TxOut`s to the address. @@ -998,14 +989,13 @@ def sendOutputs(self, outputs, keysource, utxosource, feeRate=None): changeScriptVersion = txscript.DefaultScriptVersion changeScriptSize = txscript.P2PKHPkScriptSize - relayFeePerKb = feeRate * 1e3 if feeRate else self.relayFee() for (i, txout) in enumerate(outputs): - checkOutput(txout, relayFeePerKb) + checkOutput(txout, relayFee) signedSize = txscript.estimateSerializeSize( [txscript.RedeemP2PKHSigScriptSize], outputs, changeScriptSize ) - targetFee = txscript.calcMinRequiredTxRelayFee(relayFeePerKb, signedSize) + targetFee = txscript.calcMinRequiredTxRelayFee(relayFee, signedSize) targetAmount = sum(txo.value for txo in outputs) while True: @@ -1034,7 +1024,7 @@ def sendOutputs(self, outputs, keysource, utxosource, feeRate=None): signedSize = txscript.estimateSerializeSize( scriptSizes, outputs, changeScriptSize ) - requiredFee = txscript.calcMinRequiredTxRelayFee(relayFeePerKb, signedSize) + requiredFee = txscript.calcMinRequiredTxRelayFee(relayFee, signedSize) remainingAmount = total - targetAmount if remainingAmount < requiredFee: targetFee = requiredFee @@ -1055,7 +1045,7 @@ def sendOutputs(self, outputs, keysource, utxosource, feeRate=None): changeVout = -1 changeAmount = round(total - targetAmount - requiredFee) if changeAmount != 0 and not txscript.isDustAmount( - changeAmount, changeScriptSize, relayFeePerKb + changeAmount, changeScriptSize, relayFee ): if len(changeScript) > txscript.MaxScriptElementSize: raise DecredError( @@ -1110,7 +1100,7 @@ def sendOutputs(self, outputs, keysource, utxosource, feeRate=None): return newTx, utxos, newUTXOs - def purchaseTickets(self, keysource, utxosource, req): + def purchaseTickets(self, keysource, utxosource, req, relayFee): """ Based on dcrwallet (*Wallet).purchaseTickets. purchaseTickets indicates to the wallet that a ticket should be @@ -1207,7 +1197,7 @@ def purchaseTickets(self, keysource, utxosource, req): ticketFeeIncrement = req.ticketFee if ticketFeeIncrement == 0: - ticketFeeIncrement = self.relayFee() + ticketFeeIncrement = relayFee # Make sure that we have enough funds. Calculate different # ticket required amounts depending on whether or not a @@ -1272,7 +1262,7 @@ def purchaseTickets(self, keysource, utxosource, req): txFeeIncrement = req.txFee if txFeeIncrement == 0: - txFeeIncrement = self.relayFee() + txFeeIncrement = relayFee # Send the split transaction. # sendOutputs takes the fee rate in atoms/byte @@ -1373,7 +1363,7 @@ def purchaseTickets(self, keysource, utxosource, req): ) return (splitTx, tickets), splitSpent, internalOutputs - def revokeTicket(self, tx, keysource, redeemScript): + def revokeTicket(self, tx, keysource, redeemScript, relayFee): """ Revoke a ticket by signing the supplied redeem script and broadcasting the raw transaction. @@ -1389,7 +1379,7 @@ def revokeTicket(self, tx, keysource, redeemScript): MsgTx: the signed revocation. """ - revocation = txscript.makeRevocation(tx, self.relayFee()) + revocation = txscript.makeRevocation(tx, relayFee) signedScript = txscript.signTxOutput( self.netParams, diff --git a/decred/tests/integration/dcr/test_dcrdata_live.py b/decred/tests/integration/dcr/test_dcrdata_live.py index e051184a..25a32afc 100644 --- a/decred/tests/integration/dcr/test_dcrdata_live.py +++ b/decred/tests/integration/dcr/test_dcrdata_live.py @@ -138,7 +138,7 @@ def utxosource(amt, filter): ) ticket, spent, newUTXOs = blockchain.purchaseTickets( - KeySource(), utxosource, request + KeySource(), utxosource, request, 1e4 ) finally: blockchain.close() @@ -248,5 +248,5 @@ def __init__( internal=lambda: "", ) redeemScript = ByteArray(test.redeemScript) - revocation = blockchain.revokeTicket(ticket, keysource, redeemScript) + revocation = blockchain.revokeTicket(ticket, keysource, redeemScript, 1e4) assert test.revocation == revocation.txHex() From 03b77ae643ccea82e585a94e083cee78e01ba920 Mon Sep 17 00:00:00 2001 From: JoeGruff Date: Sun, 26 Apr 2020 10:40:56 +0900 Subject: [PATCH 2/3] Make relayFee an integer everywhere. Because an atom cannot be divided, and we convert it to an integer already in a few places, it should be an integer and not a float from the beginning. Also fix docstrings. --- decred/decred/dcr/dcrdata.py | 56 +++++++++++++++++++++++++++++------ decred/decred/dcr/txscript.py | 19 +++++++----- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/decred/decred/dcr/dcrdata.py b/decred/decred/dcr/dcrdata.py index f91c4ef4..0a860941 100644 --- a/decred/decred/dcr/dcrdata.py +++ b/decred/decred/dcr/dcrdata.py @@ -852,13 +852,25 @@ def saveBlockHeader(self, header): self.heightMap[header.height] = bHash self.headerDB[bHash] = header - def sendToAddress(self, value, address, keysource, utxosource, relayFee): + def checkFeeRate(self, relayFee): + """ + Check that the relay fee is lower than the allowed max of + txscript.HighFeeRate. + """ + if relayFee > txscript.HighFeeRate: + raise DecredError( + f"relay fee of {relayFee} is above the allowed max of {txscript.HighFeeRate}" + ) + + def sendToAddress( + self, value, address, keysource, utxosource, relayFee, allowHighFees=False + ): """ Send the amount in atoms to the specified address. Args: - value int: The amount to send, in atoms. - address str: The base-58 encoded address. + value (int): The amount to send, in atoms. + address (str): The base-58 encoded address. keysource func(str) -> PrivateKey: A function that returns the private key for an address. utxosource func(int, func(UTXO) -> bool) -> list(UTXO): A function @@ -867,11 +879,18 @@ def sendToAddress(self, value, address, keysource, utxosource, relayFee): amount. If the filtering function is provided, UTXOs for which the function return a falsey value will not be included in the returned UTXO list. - MsgTx: The newly created transaction on success, `False` on failure. + relayFee (int): Transaction fees in atoms per kb. + allowHighFees (bool): Optional. Default is False. Whether to allow + fees higher than txscript.HighFeeRate. + + Returns: + MsgTx: The newly created transaction. Raises an exception on error. """ + if not allowHighFees: + self.checkFeeRate(relayFee) self.updateTip() outputs = makeOutputs([(address, value)], self.netParams) - return self.sendOutputs(outputs, keysource, utxosource, relayFee) + return self.sendOutputs(outputs, keysource, utxosource, relayFee, allowHighFees) def broadcast(self, txHex): """ @@ -953,7 +972,9 @@ def confirmUTXO(self, utxo, block=None, tx=None): pass return False - def sendOutputs(self, outputs, keysource, utxosource, relayFee): + def sendOutputs( + self, outputs, keysource, utxosource, relayFee, allowHighFees=False + ): """ Send the `TxOut`s to the address. @@ -973,12 +994,17 @@ def sendOutputs(self, outputs, keysource, utxosource, relayFee): sufficient to complete the transaction. If the filtering function is provided, UTXOs for which the function return a falsey value will not be included in the returned UTXO list. + relayFee (int): Transaction fees in atoms per kb. + allowHighFees (bool): Optional. Default is False. Whether to allow + fees higher than txscript.HighFeeRate. Returns: newTx MsgTx: The sent transaction. utxos list(UTXO): The spent UTXOs. newUTXOs list(UTXO): Length 1 array containing the new change UTXO. """ + if not allowHighFees: + self.checkFeeRate(relayFee) total = 0 inputs = [] scripts = [] @@ -1100,7 +1126,9 @@ def sendOutputs(self, outputs, keysource, utxosource, relayFee): return newTx, utxos, newUTXOs - def purchaseTickets(self, keysource, utxosource, req, relayFee): + def purchaseTickets( + self, keysource, utxosource, req, relayFee, allowHighFees=False + ): """ Based on dcrwallet (*Wallet).purchaseTickets. purchaseTickets indicates to the wallet that a ticket should be @@ -1115,6 +1143,9 @@ def purchaseTickets(self, keysource, utxosource, req, relayFee): UTXOs. The filterFunc is an optional function to filter UTXOs, and is of the form func(UTXO) -> bool. req account.TicketRequest: the ticket data. + relayFee (int): Transaction fees in atoms per kb. + allowHighFees (bool): Optional. Default is False. Whether to allow + fees higher than txscript.HighFeeRate. Returns: (splitTx, tickets) tuple: first element is the split transaction. @@ -1125,6 +1156,8 @@ def purchaseTickets(self, keysource, utxosource, req, relayFee): addresses. """ + if not allowHighFees: + self.checkFeeRate(relayFee) self.updateTip() # account minConf is zero for regular outputs for now. Need to make that # adjustable. @@ -1267,7 +1300,7 @@ def purchaseTickets(self, keysource, utxosource, req, relayFee): # Send the split transaction. # sendOutputs takes the fee rate in atoms/byte splitTx, splitSpent, internalOutputs = self.sendOutputs( - splitOuts, keysource, utxosource, int(txFeeIncrement / 1000) + splitOuts, keysource, utxosource, txFeeIncrement // 1000, allowHighFees ) # Generate the tickets individually. @@ -1363,7 +1396,7 @@ def purchaseTickets(self, keysource, utxosource, req, relayFee): ) return (splitTx, tickets), splitSpent, internalOutputs - def revokeTicket(self, tx, keysource, redeemScript, relayFee): + def revokeTicket(self, tx, keysource, redeemScript, relayFee, allowHighFees=False): """ Revoke a ticket by signing the supplied redeem script and broadcasting the raw transaction. @@ -1374,10 +1407,15 @@ def revokeTicket(self, tx, keysource, redeemScript, relayFee): the private key used for signing. redeemScript (byte-like): the 1-of-2 multisig script that delegates voting rights for the ticket. + relayFee (int): Transaction fees in atoms per kb. + allowHighFees (bool): Optional. Default is False. Whether to allow + fees higher than txscript.HighFeeRate. Returns: MsgTx: the signed revocation. """ + if not allowHighFees: + self.checkFeeRate(relayFee) revocation = txscript.makeRevocation(tx, relayFee) diff --git a/decred/decred/dcr/txscript.py b/decred/decred/dcr/txscript.py index 9c80bbbe..fc5dc499 100644 --- a/decred/decred/dcr/txscript.py +++ b/decred/decred/dcr/txscript.py @@ -154,7 +154,10 @@ # to maintain reference. # DefaultRelayFeePerKb is the default minimum relay fee policy for a mempool. -DefaultRelayFeePerKb = 1e4 +DefaultRelayFeePerKb = int(1e4) + +# HighFeeRate is the atoms/kb rate that is considered too high. +HighFeeRate = DefaultRelayFeePerKb * 1000 # MaxStandardTxSize is the maximum size allowed for transactions that are # considered standard and will therefore be relayed and considered for mining. @@ -2605,7 +2608,7 @@ def paysHighFees(totalInput, tx): # Impossible to determine return False - maxFee = calcMinRequiredTxRelayFee(1000 * DefaultRelayFeePerKb, tx.serializeSize()) + maxFee = calcMinRequiredTxRelayFee(HighFeeRate, tx.serializeSize()) return fee > maxFee @@ -3406,7 +3409,7 @@ def calcMinRequiredTxRelayFee(relayFeePerKb, txSerializeSize): pool and relayed. Args: - relayFeePerKb (float): The fee per kilobyte. + relayFeePerKb (int): The fee in atoms per kilobyte. txSerializeSize int: (Size) of the byte-encoded transaction. Returns: @@ -3436,7 +3439,7 @@ def isDustAmount(amount, scriptSize, relayFeePerKb): Args: amount (int): Atoms. scriptSize (int): Byte-size of the script. - relayFeePerKb (float): Fees paid per kilobyte. + relayFeePerKb (int): Fees paid in atoms per kilobyte. Returns: bool: True if the amount is considered dust. @@ -3495,7 +3498,7 @@ def isDustOutput(output, relayFeePerKb): Args: output (wire.TxOut): The transaction output. - relayFeePerKb: Minimum transaction fee allowable. + relayFeePerKb (int): The transaction fee in atoms per kb. Returns: bool: True if output is a dust output. @@ -3770,7 +3773,7 @@ def stakePoolTicketFee(stakeDiff, relayFee, height, poolFee, subsidyCache, netPa Args: stakeDiff (int): The ticket price. - relayFee (int): Transaction fees. + relayFee (int): Transaction fees in atoms per kb. height (int): Current block height. poolFee (int): The pools fee, as percent. subsidyCache (calc.SubsidyCache): A subsidy cache. @@ -3805,8 +3808,8 @@ def stakePoolTicketFee(stakeDiff, relayFee, height, poolFee, subsidyCache, netPa # The numerator is (p*10000*s*(v+z)) << 64. shift = 64 s = subsidy - v = int(stakeDiff) - z = int(relayFee) + v = stakeDiff + z = relayFee num = poolFeeInt num *= s vPlusZ = v + z From 9a686f5cab63ef8c96088355d1d64bdcba2b64fd Mon Sep 17 00:00:00 2001 From: JoeGruff Date: Mon, 27 Apr 2020 14:49:51 +0900 Subject: [PATCH 3/3] Remove relayFee parameter from purchaseTickets. The relay fee is already included in the req, which the caller has defined. They can change the relay fee there. --- decred/decred/dcr/account.py | 54 +++++++++++++++++++++-------------- decred/decred/dcr/dcrdata.py | 25 +++++----------- decred/decred/dcr/txscript.py | 2 +- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/decred/decred/dcr/account.py b/decred/decred/dcr/account.py index ec65dbad..19cca01b 100644 --- a/decred/decred/dcr/account.py +++ b/decred/decred/dcr/account.py @@ -89,37 +89,43 @@ def __init__( spendLimit, poolAddress, votingAddress, - ticketFee, poolFees, count, txFee, + ticketFee=0, ): - # minConf is just a placeholder for now. Account minconf is 0 until - # I add the ability to change it. + """ + TicketRequest constructor. + + Args: + minConf (int): minConf is just a placeholder for now. Account + minconf is 0 until I add the ability to change it. + expiry (int): expiry can be set to some reasonable block height. + This may be important when approaching the end of a ticket + window. + spendLimit (int): Price is calculated purely from the ticket count, + price, and fees, but cannot go over spendLimit. + poolAddress (str): The VSP fee payment address. + votingAddress (str): The P2SH voting address based on the 1-of-2. + multi-sig script you share with the VSP. + poolFees (int): poolFees are set by the VSP. If you don't set these + correctly, the VSP may not vote for you. + count (int): How many tickets to buy. + txFee (int): txFee is the transaction fee rate to pay the miner for + the split transaction required to fund the ticket. + ticketFee (int): Optional. Default is the network's default relay + fee. ticketFee is the transaction fee rate to pay the miner for + the ticket. + """ self.minConf = minConf - # expiry can be set to some reasonable block height. This may be - # important when approaching the end of a ticket window. self.expiry = expiry - # Price is calculated purely from the ticket count, price, and fees, but - # cannot go over spendLimit. self.spendLimit = spendLimit - # The VSP fee payment address. self.poolAddress = poolAddress - # The P2SH voting address based on the 1-of-2 multi-sig script you share - # with the VSP. self.votingAddress = votingAddress - # ticketFee is the transaction fee rate to pay the miner for the ticket. - # Set to zero to use wallet's network default fee rate. - self.ticketFee = ticketFee - # poolFees are set by the VSP. If you don't set these correctly, the - # VSP may not vote for you. self.poolFees = poolFees - # How many tickets to buy. self.count = count - # txFee is the transaction fee rate to pay the miner for the split - # transaction required to fund the ticket. - # Set to zero to use wallet's network default fee rate. self.txFee = txFee + self.ticketFee = ticketFee if ticketFee != 0 else DefaultRelayFeePerKb class TicketStats: @@ -1895,6 +1901,13 @@ def purchaseTickets(self, qty, price): Account uses the blockchain to do the heavy lifting, but must prepare the TicketRequest and KeySource and gather some other account- related information. + + Args: + qty (int): The number of tickets to buy. + price (int): The price per ticket in coins to pay. + + Returs: + MsgTx: The sent split transaction. """ keysource = KeySource( priv=self.privKeyForAddress, internal=self.nextInternalAddress, @@ -1907,13 +1920,12 @@ def purchaseTickets(self, qty, price): spendLimit=int(round(price * qty * 1.1 * 1e8)), # convert to atoms here poolAddress=pi.poolAddress, votingAddress=pi.ticketAddress, - ticketFee=DefaultRelayFeePerKb, poolFees=pi.poolFees, count=qty, txFee=self.relayFee, ) txs, spentUTXOs, newUTXOs = self.blockchain.purchaseTickets( - keysource, self.getUTXOs, req, self.relayFee + keysource, self.getUTXOs, req ) # Add the split transactions self.addMempoolTx(txs[0]) diff --git a/decred/decred/dcr/dcrdata.py b/decred/decred/dcr/dcrdata.py index 0a860941..ffa5f698 100644 --- a/decred/decred/dcr/dcrdata.py +++ b/decred/decred/dcr/dcrdata.py @@ -1126,9 +1126,7 @@ def sendOutputs( return newTx, utxos, newUTXOs - def purchaseTickets( - self, keysource, utxosource, req, relayFee, allowHighFees=False - ): + def purchaseTickets(self, keysource, utxosource, req, allowHighFees=False): """ Based on dcrwallet (*Wallet).purchaseTickets. purchaseTickets indicates to the wallet that a ticket should be @@ -1138,12 +1136,11 @@ def purchaseTickets( available. Args: - keysource account.KeySource: a source for private keys. + keysource (account.KeySource): a source for private keys. utxosource func(int, filterFunc) -> (list(UTXO), bool): a source for UTXOs. The filterFunc is an optional function to filter UTXOs, and is of the form func(UTXO) -> bool. - req account.TicketRequest: the ticket data. - relayFee (int): Transaction fees in atoms per kb. + req (account.TicketRequest): the ticket data. allowHighFees (bool): Optional. Default is False. Whether to allow fees higher than txscript.HighFeeRate. @@ -1157,7 +1154,8 @@ def purchaseTickets( """ if not allowHighFees: - self.checkFeeRate(relayFee) + self.checkFeeRate(req.txFee) + self.checkFeeRate(req.ticketFee) self.updateTip() # account minConf is zero for regular outputs for now. Need to make that # adjustable. @@ -1228,10 +1226,6 @@ def purchaseTickets( "unsupported voting address type %s" % votingAddress.__class__.__name__ ) - ticketFeeIncrement = req.ticketFee - if ticketFeeIncrement == 0: - ticketFeeIncrement = relayFee - # Make sure that we have enough funds. Calculate different # ticket required amounts depending on whether or not a # pool output is needed. If the ticket fee increment is @@ -1255,7 +1249,7 @@ def purchaseTickets( ] estSize = txscript.estimateSerializeSizeFromScriptSizes(inSizes, outSizes, 0) - ticketFee = txscript.calcMinRequiredTxRelayFee(ticketFeeIncrement, estSize) + ticketFee = txscript.calcMinRequiredTxRelayFee(req.ticketFee, estSize) neededPerTicket = ticketFee + ticketPrice # If we need to calculate the amount for a pool fee percentage, @@ -1293,14 +1287,9 @@ def purchaseTickets( # User amount. splitOuts.append(msgtx.TxOut(value=userAmt, pkScript=splitPkScript,)) - txFeeIncrement = req.txFee - if txFeeIncrement == 0: - txFeeIncrement = relayFee - # Send the split transaction. - # sendOutputs takes the fee rate in atoms/byte splitTx, splitSpent, internalOutputs = self.sendOutputs( - splitOuts, keysource, utxosource, txFeeIncrement // 1000, allowHighFees + splitOuts, keysource, utxosource, req.txFee, allowHighFees ) # Generate the tickets individually. diff --git a/decred/decred/dcr/txscript.py b/decred/decred/dcr/txscript.py index fc5dc499..cab1b4be 100644 --- a/decred/decred/dcr/txscript.py +++ b/decred/decred/dcr/txscript.py @@ -3410,7 +3410,7 @@ def calcMinRequiredTxRelayFee(relayFeePerKb, txSerializeSize): Args: relayFeePerKb (int): The fee in atoms per kilobyte. - txSerializeSize int: (Size) of the byte-encoded transaction. + txSerializeSize (int): Size of the byte-encoded transaction. Returns: int: Fee in atoms.