# Verifying change
With bitpost, you can create child transactions of PSTs previously relayed to us. To do this, you will probably want to query what change is available from ongoing requests with the /utxos
endpoint. Unless showunknownchange
is set to true, the provided utxos will just contain the change utxos (guessed from the fee being discounted in them or specified by the user), which the user can verify as being spendable by him. If showrawtx
is set to true, the user can perform two additional verifications: verify that the all the provided change belongs to mutually exclusive pre-signed transactions (PSTs), so that a double spend is impossible; and to verify that the provided PSTs are valid.
Although we think that the last two types of verification are mostly unecessary and don't justify the extra bandwith, we encourage the philisophy of "don't trust, verify".
# Verifying spendability
The answer to /utxos
will provide the scriptPubKey of every change (often the same). You can then query your wallet if this scriptPuKey/address belongs to it. With a bitcoin core wallet you can check spendability with:
bitcoin-cli getaddressinfo $(bitcoin-cli decodescript 'YOUR_SCRIPT' | jq .addresses[0] | tr -d '"') | jq .solvable
In the case of bit, the library we have used to provide code examples, it doesn't support BIP 32 wallets, so we just have to check if its address is equal to the private key's P2PKH or P2SH(PWPKH) address.
from binascii import unhexlify
import bit
from bitcoin.core.script import CScript # python-bitcoinlib: https://pypi.org/project/python-bitcoinlib
from bitcoin.wallet import CBitcoinAddress
CHANGE_SCRIPT = 'a914406fea471691f061ac2a7ee1065e157a0acaeed787' # replace with yours
scriptPubKey = CScript(unhexlify(CHANGE_SCRIPT))
addr = CBitcoinAddress.from_scriptPubKey(scriptPubKey)
key = bit.Key.from_bytes(b'REPLACE_WITH_YOUR_PRIVATE_KEY')
print('matches segwit address={}, matches legacy address={}'.format(str(addr) == key.segwit_address, str(addr) == key.address))
# Verifying mutual exclusivity
This type of verification tells you whether the change UTXOs provided by Bitpost are mutually exclusive or not. By construction, it should be impossible for them not to be, as this is checked every time new PSTs are relayed. If you wish to do this verification, the showrawtx=true
option should be passed when calling the /utxos
endpoint. The code below how you can perform this verification - it uses our pyhton interface and bit.
# class under https://github.com/bitpostAPI/examples
from bit_integration.bitpos_interface_for_bit import BipostInterfaceForBit
bitpostInterface = BipostInterfaceForBit('YOUR_WALLETTOKEN')
result, message = bitpostInterface.verify_change()
if result:
print("Successfully verified that change utxos are mutually exclusive. Child transaction are double-spend safe!")
else:
# This should NEVER happen. If it ever does during the beta, please get in touch immediately
print("Verification failed! Change utxos are not multiple exclusive. Error message=" + message)
# Verifying validity
This form of verification is the hardest to implement and may be labor-intensive in the general case. However, this task is often simplified because the relayed PSTs are signed by only one party or belong to a small set of common transaction types. Right now, we don't provide any code examples for this. If you want to do this type of verification and are struggling, even with the tips below, get in touch.
Verifying that scriptSig and witness fields can unlock the scriptPubKey can usually be done, without broadcasting, via the testmempoolaccept
RPC command of bitcoin core. However, this command will reply "false, missing inputs" if a pre-signed transaction spends from another, which is not yet in the mempool or mined. A pull request has been made to account for this case, but it hasn't been merged or bundled in a release at the time of writing.
Many bitcoin libraries like bitcoinJ and python-bitcoinlib offer a script interpreter that can validate a particular scriptPubKey against a scriptSig/witness. Still, they require some "verification flags" as additional input. So if you want to be able to check every type of transaction, you might need to build your own "verification flag factory".
WARNING
In many bitcoin libraries, the method transaction.verify()
, one exception being 1200wd's bitcoinlib, only does some very basic sanity checks on the transaction.
When the transactions relayed to Bitpost are signed by a single party (excluding e.g. multisig), there is a hacky way of verifying the validity of the PSTs: clear the signatures (scriptSig and witness fields) and sign the transactions again. If the new PSTs are equal to the old PSTs, then the PSTs provided by us are had valid signatures.