Skip to content

Commit

Permalink
Correct fee estimation.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeGruffins committed Dec 3, 2020
1 parent 4b9f8e5 commit ddb2ea2
Showing 1 changed file with 43 additions and 15 deletions.
58 changes: 43 additions & 15 deletions decred/examples/drain_xpriv.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
from urllib.parse import urlunsplit

from base58 import b58decode, b58encode
from base58 import b58decode
from decred import DecredError
from decred.crypto import crypto
from decred.crypto.secp256k1.curve import curve as Curve
Expand All @@ -29,9 +29,11 @@ def cfg(isTestnet):
cfgPath = os.path.join(dcrdCfgDir, "dcrd.conf")
if not os.path.isfile(cfgPath):
return None
cfg = helpers.readINI(cfgPath, ["rpcuser", "rpcpass", "rpccert"])
cfg = helpers.readINI(cfgPath, ["rpcuser", "rpcpass", "rpccert", "addrindex"])
assert "rpcuser" in cfg
assert "rpcpass" in cfg
if "addrindex" not in cfg or not cfg["addrindex"]:
raise DecredError("addrindex must be enabled")
if "rpccert" not in cfg:
cfg["rpccert"] = os.path.join(dcrdCfgDir, "rpc.cert")
if "rpclisten" not in cfg:
Expand Down Expand Up @@ -114,12 +116,12 @@ def getUTXOs(node, key, net):
idx, txGap = 0, 0
utxos = []
while txGap < GAP_LIMIT:
addr = ""
try:
addr = addrlib.deriveChildAddress(key, idx, net)
except Exception:
# Very small chance of a bad address.
pass
idx += 1
continue
try:
res = node.searchRawTransactions(addr, verbose=True)
for rawTx in res:
Expand Down Expand Up @@ -176,11 +178,19 @@ def signUTXOs(node, utxos, sendToAddr, totalValue, net):
expiry=0,
cachedHash=None,
)
fee = txscript.calcMinRequiredTxRelayFee(FEE_RATE, newTx.serializeSize())

size = txscript.estimateSerializeSize(
[txscript.RedeemP2PKHSigScriptSize for _ in inputs], [output], 0
)
fee = txscript.calcMinRequiredTxRelayFee(FEE_RATE, size)

if fee > totalValue:
raise DecredError("Not enough funds to cover the transaction fee.")

newTx.txOut[0].value = totalValue - int(fee)
output.value = totalValue - int(fee)

if txscript.isDustOutput(output, FEE_RATE):
raise DecredError("Transaction is considered dust. Not sending.")

for idx, utxo in enumerate(utxos):
signatureScript, _, _, _ = txscript.sign(
Expand All @@ -201,22 +211,24 @@ def main():
net = None
isTestnet = False
tString = ""
netStr = input("Is this mainnet or testnet?\n")
if netStr in ["testnet", "test", "t"]:
netStr = input("Is this mainnet or testnet? (m/t)\n")
if netStr in ("testnet", "test", "t"):
net = nets.testnet
isTestnet = True
tString = "t"
elif netStr in ["mainnet", "main", "m"]:
elif netStr in ("mainnet", "main", "m"):
net = nets.mainnet
else:
raise DecredError("Unknown network entered.")

xprivStr = input("Enter xpriv: ")
xpriv = decodeExtendedKey(net, xprivStr)
# Double check that we can reproduce the xpriv.
if b58encode(xpriv.serialize().b).decode() != xprivStr:
if xpriv.string() != xprivStr:
raise DecredError("unknown xpriv parsing error")

# Printing a newline.
print()
internal = xpriv.child(INTERNAL)
external = xpriv.child(EXTERNAL)

Expand All @@ -237,17 +249,33 @@ def main():

print(f"Found {len(utxos)} outputs totalling {totalValue} {tString}dcr.\n")

sendToAddrStr = input("Input address to send funds: ")
# Will throw if bad addr.
sendToAddr = addrlib.decodeAddress(sendToAddrStr, net)
while True:
sendToAddrStr = input("Input address to send funds: ")
print()
try:
# Will throw if bad addr.
sendToAddr = addrlib.decodeAddress(sendToAddrStr, net)
break
except Exception as e:
print(e)
tryAgain = input("\nBad address. Try again? (y/n)\n")
if tryAgain not in ("y", "yes"):
print("Aborted")
return

signedTx = signUTXOs(node, utxos, sendToAddr, int(totalValue * 1e8), net)

# Double check output script address.
_, gotAddrs, _ = txscript.extractPkScriptAddrs(0, signedTx.txOut[0].pkScript, net)
if gotAddrs[0].address() != sendToAddrStr:
raise DecredError("unknown output address parsing error")

print(f"Got the raw hex: {signedTx.serialize().hex()}")
print(f"{repr(signedTx)}\n")
doIt = input(f"Really send funds to {sendToAddrStr}?\n")
doIt = input(f"Really send funds to {sendToAddrStr}? (y/n)\n")
if doIt in ("yes", "y"):
txid = node.sendRawTransaction(signedTx)
print(f"Sent transaction: {reversed(txid).hex()}")
print(f"\nSent transaction: {reversed(txid).hex()}")
else:
print("Aborted.")

Expand Down

0 comments on commit ddb2ea2

Please sign in to comment.