Fix BTC witness size estimate.

This commit is contained in:
tecnovert
2023-07-14 09:31:05 +02:00
parent 705ac2c6fc
commit 7bc5fc78ba
12 changed files with 143 additions and 54 deletions

View File

@@ -351,7 +351,7 @@ class BTCInterface(CoinInterface):
if self.sc._restrict_unknown_seed_wallets:
ensure(addr_info['hdseedid'] == self._expect_seedid_hex, 'unexpected seedid')
def get_fee_rate(self, conf_target=2):
def get_fee_rate(self, conf_target: int = 2):
try:
fee_rate = self.rpc_callback('estimatesmartfee', [conf_target])['feerate']
assert (fee_rate > 0.0), 'Non positive feerate'
@@ -410,8 +410,8 @@ class BTCInterface(CoinInterface):
assert (len(pk) == 33)
return self.pkh_to_address(hash160(pk))
def getNewSecretKey(self):
return getSecretInt()
def getNewSecretKey(self) -> bytes:
return i2b(getSecretInt())
def getPubkey(self, privkey):
return PublicKey.from_secret(privkey).format()
@@ -486,7 +486,7 @@ class BTCInterface(CoinInterface):
def fundSCLockTx(self, tx_bytes, feerate, vkbv=None):
return self.fundTx(tx_bytes, feerate)
def extractScriptLockRefundScriptValues(self, script_bytes):
def extractScriptLockRefundScriptValues(self, script_bytes: bytes):
script_len = len(script_bytes)
ensure(script_len > 73, 'Bad script length')
ensure_op(script_bytes[0] == OP_IF)
@@ -517,7 +517,7 @@ class BTCInterface(CoinInterface):
return pk1, pk2, csv_val, pk3
def genScriptLockRefundTxScript(self, Kal, Kaf, csv_val):
def genScriptLockRefundTxScript(self, Kal, Kaf, csv_val) -> CScript:
Kal_enc = Kal if len(Kal) == 33 else self.encodePubkey(Kal)
Kaf_enc = Kaf if len(Kaf) == 33 else self.encodePubkey(Kaf)
@@ -553,7 +553,7 @@ class BTCInterface(CoinInterface):
dummy_witness_stack = self.getScriptLockTxDummyWitness(script_lock)
witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
pay_fee = int(tx_fee_rate * vsize // 1000)
pay_fee = round(tx_fee_rate * vsize / 1000)
tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash()
@@ -588,7 +588,7 @@ class BTCInterface(CoinInterface):
dummy_witness_stack = self.getScriptLockRefundSpendTxDummyWitness(script_lock_refund)
witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
pay_fee = int(tx_fee_rate * vsize // 1000)
pay_fee = round(tx_fee_rate * vsize / 1000)
tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash()
@@ -624,7 +624,7 @@ class BTCInterface(CoinInterface):
dummy_witness_stack = self.getScriptLockRefundSwipeTxDummyWitness(script_lock_refund)
witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
pay_fee = int(tx_fee_rate * vsize // 1000)
pay_fee = round(tx_fee_rate * vsize / 1000)
tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash()
@@ -633,7 +633,7 @@ class BTCInterface(CoinInterface):
return tx.serialize()
def createSCLockSpendTx(self, tx_lock_bytes, script_lock, pkh_dest, tx_fee_rate, vkbv=None):
def createSCLockSpendTx(self, tx_lock_bytes, script_lock, pkh_dest, tx_fee_rate, vkbv=None, fee_info={}):
tx_lock = self.loadTx(tx_lock_bytes)
output_script = self.getScriptDest(script_lock)
locked_n = findOutput(tx_lock, output_script)
@@ -653,9 +653,14 @@ class BTCInterface(CoinInterface):
dummy_witness_stack = self.getScriptLockTxDummyWitness(script_lock)
witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
pay_fee = int(tx_fee_rate * vsize // 1000)
pay_fee = round(tx_fee_rate * vsize / 1000)
tx.vout[0].nValue = locked_coin - pay_fee
fee_info['fee_paid'] = pay_fee
fee_info['rate_used'] = tx_fee_rate
fee_info['witness_bytes'] = witness_bytes
fee_info['vsize'] = vsize
tx.rehash()
self._log.info('createSCLockSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
@@ -1070,7 +1075,7 @@ class BTCInterface(CoinInterface):
def getBLockSpendTxFee(self, tx, fee_rate: int) -> int:
witness_bytes = 109
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
pay_fee = int(fee_rate * vsize // 1000)
pay_fee = round(fee_rate * vsize / 1000)
self._log.info(f'BLockSpendTx fee_rate, vsize, fee: {fee_rate}, {vsize}, {pay_fee}.')
return pay_fee
@@ -1244,37 +1249,37 @@ class BTCInterface(CoinInterface):
# Only one prevout exists
return 0
def getScriptLockTxDummyWitness(self, script):
def getScriptLockTxDummyWitness(self, script: bytes):
return [
b''.hex(),
bytes(72).hex(),
bytes(72).hex(),
bytes(len(script)).hex()
b'',
bytes(72),
bytes(72),
bytes(len(script))
]
def getScriptLockRefundSpendTxDummyWitness(self, script):
def getScriptLockRefundSpendTxDummyWitness(self, script: bytes):
return [
b''.hex(),
bytes(72).hex(),
bytes(72).hex(),
bytes((1,)).hex(),
bytes(len(script)).hex()
b'',
bytes(72),
bytes(72),
bytes((1,)),
bytes(len(script))
]
def getScriptLockRefundSwipeTxDummyWitness(self, script):
def getScriptLockRefundSwipeTxDummyWitness(self, script: bytes):
return [
bytes(72).hex(),
b''.hex(),
bytes(len(script)).hex()
bytes(72),
b'',
bytes(len(script))
]
def getWitnessStackSerialisedLength(self, witness_stack):
length = getCompactSizeLen(len(witness_stack))
for e in witness_stack:
length += getWitnessElementLen(len(e) // 2) # hex -> bytes
length += getWitnessElementLen(len(e))
# See core SerializeTransaction
length += 32 + 4 + 1 + 4 # vinDummy
length += 1 # vinDummy
length += 1 # flags
return length