Skip to content

Instantly share code, notes, and snippets.

@NicolasFlamel1
Last active June 11, 2023 09:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NicolasFlamel1/56becb6beb5c9cdc0f2f1d457f379f7d to your computer and use it in GitHub Desktop.
Save NicolasFlamel1/56becb6beb5c9cdc0f2f1d457f379f7d to your computer and use it in GitHub Desktop.
# This demonstrates how to use the secp256k1-zkp-mw Python module, https://github.com/grinventions/secp256k1-zkp-mw, to find all the unspent Grin outputs belonging to a wallet. This code lacks any error checking. A wallet's rewind hash can be obtained by running the command `grin-wallet rewind_hash` with the Grin CLI wallet, https://github.com/mimblewimble/grin-wallet.
# Imports
from secp256k1_zkp_mw import *
from hashlib import blake2b
import requests
# Constants
# Rewind hash
REWIND_HASH = bytes.fromhex('99d92c1264de3edab618eeeb024533447c30c4d6549d70efc745fe385bd2862b')
# Server
SERVER = 'https://grinnode.live:3413'
# Functions
# Format number
def formatNumber(number):
# Return formatted number
return '{:.9f}'.format(number / 1E9).rstrip('0').rstrip('.')
# Main function
# Create context
context = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN)
# Get the tip height from the node
tipHeight = requests.post(SERVER + '/v2/foreign', json = {
'jsonrpc': '2.0',
'id': 1,
'method': 'get_tip',
'params': []
}).json()['result']['Ok']['height']
# Display start message
print('Scanning up to height %d for unspent outputs belonging to the wallet with the rewind hash %s. This may take a while.' % (tipHeight, REWIND_HASH.hex()))
# Get the PMMR indices from the genesis block to the tip height from the node
pmmrIndices = requests.post(SERVER + '/v2/foreign', json = {
'jsonrpc': '2.0',
'id': 1,
'method': 'get_pmmr_indices',
'params': [
0,
tipHeight
]
}).json()['result']['Ok']
# Get start and end indices from the PMMR indices
startIndex = pmmrIndices['last_retrieved_index']
endIndex = pmmrIndices['highest_index']
# Go through all unspent outputs in the PMMR indices range
while True:
# Get the next group of unspent outputs from the node
unspentOutputs = requests.post(SERVER + '/v2/foreign', json = {
'jsonrpc': '2.0',
'id': 1,
'method': 'get_unspent_outputs',
'params': [
startIndex,
endIndex,
1000,
True
]
}).json()['result']['Ok']
# Go through all unspent outputs in the group
for unspentOutput in unspentOutputs['outputs']:
# Get commit and proof from the unspent output
commit = bytes.fromhex(unspentOutput['commit'])
proof = bytes.fromhex(unspentOutput['proof'])
# Get rewind nonce for the commit
rewindNonce = blake2b(REWIND_HASH, digest_size = 32, key = commit).digest()
# Check if the unspent output belongs to the wallet
internalCommit = secp256k1_pedersen_commitment_parse(context, commit)
outputData = secp256k1_bulletproof_rangeproof_rewind(context, proof, 0, internalCommit, secp256k1_generator_const_h, rewindNonce, None)
if outputData is not None:
# Get amount from the output data
amount = outputData[0]
# Display unspent output found message
print('Found an unspent output with %s Grin at height %d.' % (formatNumber(amount), unspentOutput['block_height']))
# Check if no more unspent outputs exist in the range
if unspentOutputs['highest_index'] <= unspentOutputs['last_retrieved_index']:
# Break
break
# Update start index
startIndex = unspentOutputs['last_retrieved_index'] + 1
# Display end message
print('Done scanning for unspent outputs.')
# Destroy the context
secp256k1_context_destroy(context)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment