importjsonimportosimporttimeimporturllib.errorimporturllib.requestNODE_URL=os.getenv("NODE_URL","http://libertalia.nemtest.net:7890")print(f'Using node {NODE_URL}')# Transaction hash to monitortransaction_hash=os.getenv("TRANSACTION_HASH","AE0B2142DFB75C9C126442EF612944E926BCE63FA34B353CDE409E2E87703C0B")# Signer's addresssigner_address=os.getenv("SIGNER_ADDRESS","TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP")# Transaction signaturetransaction_signature=os.getenv("TRANSACTION_SIGNATURE","99B1850FADDB964112D030AA0A5C9F8B5B1B6B992B407D9C70F52F089BD651DF""A7D4991639A48B810EFD98C45060D7AD9AE57FDA37F58561459DCE8D0A747F02")print(f"Monitoring transaction: {transaction_hash}")defget_confirmation_height(tx_hash):""" Query /transaction/get once to check for confirmation. Args: tx_hash: hash of the transaction to check Returns: The height of the block containing the transaction, or None if the transaction is not confirmed yet """url=f"{NODE_URL}/transaction/get?hash={tx_hash}"try:withurllib.request.urlopen(url)asresponse:confirmed=json.loads(response.read().decode())returnconfirmed["meta"]["height"]excepturllib.error.HTTPErroraserr:iferr.status!=400:raisereturnNonedefis_in_unconfirmed_pool(signature,address):""" Check whether a transaction with the given signature is in the address's unconfirmed pool. """path=f"/account/unconfirmedTransactions?address={address}"withurllib.request.urlopen(f"{NODE_URL}{path}")asresponse:pool=json.loads(response.read().decode())["data"]target=signature.lower()returnany(entry["transaction"]["signature"].lower()==targetforentryinpool)defwait_for_confirmation(tx_hash,max_attempts=120,wait_seconds=1):""" Check for confirmation repeatedly until the transaction is confirmed or the attempts run out. Args: tx_hash: hash of the transaction to monitor max_attempts: maximum polling attempts wait_seconds: seconds to wait between attempts Returns: True if the transaction was confirmed, False otherwise """print("\nWaiting for transaction confirmation")forattemptinrange(1,max_attempts+1):time.sleep(wait_seconds)height=get_confirmation_height(tx_hash)status=f"confirmed in block {height}"ifheightelse"pending"print(f" Attempt {attempt}: {status}")ifheight:returnTruereturnFalsetry:block_height=get_confirmation_height(transaction_hash)ifblock_height:print(f"\nTransaction confirmed in block {block_height}")elifnotis_in_unconfirmed_pool(transaction_signature,signer_address):print("\nTransaction not found")elifwait_for_confirmation(transaction_hash):print("\nTransaction confirmed!")else:print("\nTransaction not confirmed within the polling window")excepturllib.error.URLErroraserr:print(f"\nCould not reach the node: {err.reason}")
constNODE_URL=process.env.NODE_URL||'http://libertalia.nemtest.net:7890';console.log('Using node',NODE_URL);// Transaction hash to monitor.consttransactionHash=process.env.TRANSACTION_HASH||'AE0B2142DFB75C9C126442EF612944E926BCE63FA34B353CDE409E2E87703C0B';// Signer's address.constsignerAddress=process.env.SIGNER_ADDRESS||'TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP';// Transaction signature.consttransactionSignature=process.env.TRANSACTION_SIGNATURE||'99B1850FADDB964112D030AA0A5C9F8B5B1B6B992B407D9C70F52F089BD651DF'+'A7D4991639A48B810EFD98C45060D7AD9AE57FDA37F58561459DCE8D0A747F02';console.log(`Monitoring transaction: ${transactionHash}`);/** * Query /transaction/get once to check for confirmation. * @param {string} txHash - hash of the transaction to check * @returns {number|null} height of the block containing the * transaction, or null if it is not confirmed yet */asyncfunctiongetConfirmationHeight(txHash){consturl=`${NODE_URL}/transaction/get?hash=${txHash}`;constresponse=awaitfetch(url);if(response.ok){constconfirmed=awaitresponse.json();returnconfirmed.meta.height;}if(400!==response.status)thrownewError(`Unexpected status: ${response.status}`);returnnull;}/** * Check whether a transaction with the given signature is in the * address's unconfirmed pool. * @param {string} signature - hex signature of the monitored transaction * @param {string} address - signer's address * @returns {boolean} true if the signature is in the signer's pool */asyncfunctionisInUnconfirmedPool(signature,address){constpath=`/account/unconfirmedTransactions?address=${address}`;constresponse=awaitfetch(`${NODE_URL}${path}`);constpool=(awaitresponse.json()).data;consttarget=signature.toLowerCase();returnpool.some(entry=>entry.transaction.signature.toLowerCase()===target);}/** * Check for confirmation repeatedly until the transaction is * confirmed or the attempts run out. * @param {string} txHash - hash of the transaction to monitor * @param {number} maxAttempts - maximum polling attempts * @param {number} waitSeconds - seconds to wait between attempts * @returns {boolean} true if the transaction was confirmed */asyncfunctionwaitForConfirmation(txHash,maxAttempts=120,waitSeconds=1){console.log('\nWaiting for transaction confirmation');for(letattempt=1;attempt<=maxAttempts;attempt++){awaitnewPromise(resolve=>{setTimeout(resolve,waitSeconds*1000);});constheight=awaitgetConfirmationHeight(txHash);conststatus=height?`confirmed in block ${height}`:'pending';console.log(` Attempt ${attempt}: ${status}`);if(height)returntrue;}returnfalse;}try{constblockHeight=awaitgetConfirmationHeight(transactionHash);if(blockHeight)console.log(`\nTransaction confirmed in block ${blockHeight}`);elseif(!(awaitisInUnconfirmedPool(transactionSignature,signerAddress)))console.log('\nTransaction not found');elseif(awaitwaitForConfirmation(transactionHash))console.log('\nTransaction confirmed!');elseconsole.log('\nConfirmation timed out');}catch(error){console.log(`\nCould not reach the node: ${error.message}`);}
defget_confirmation_height(tx_hash):""" Query /transaction/get once to check for confirmation. Args: tx_hash: hash of the transaction to check Returns: The height of the block containing the transaction, or None if the transaction is not confirmed yet """url=f"{NODE_URL}/transaction/get?hash={tx_hash}"try:withurllib.request.urlopen(url)asresponse:confirmed=json.loads(response.read().decode())returnconfirmed["meta"]["height"]excepturllib.error.HTTPErroraserr:iferr.status!=400:raisereturnNone
/** * Query /transaction/get once to check for confirmation. * @param {string} txHash - hash of the transaction to check * @returns {number|null} height of the block containing the * transaction, or null if it is not confirmed yet */asyncfunctiongetConfirmationHeight(txHash){consturl=`${NODE_URL}/transaction/get?hash=${txHash}`;constresponse=awaitfetch(url);if(response.ok){constconfirmed=awaitresponse.json();returnconfirmed.meta.height;}if(400!==response.status)thrownewError(`Unexpected status: ${response.status}`);returnnull;}
それ以外の場合、エンドポイントは HTTP 400(「Hash was not found in cache」)を返し、関数は高さを返しません。これはトランザクションが承認されていないことを意味します。
承認されていないトランザクションは 未承認トランザクションプール で承認を待っている可能性があり、次の関数が確認します。
defis_in_unconfirmed_pool(signature,address):""" Check whether a transaction with the given signature is in the address's unconfirmed pool. """path=f"/account/unconfirmedTransactions?address={address}"withurllib.request.urlopen(f"{NODE_URL}{path}")asresponse:pool=json.loads(response.read().decode())["data"]target=signature.lower()returnany(entry["transaction"]["signature"].lower()==targetforentryinpool)
/** * Check whether a transaction with the given signature is in the * address's unconfirmed pool. * @param {string} signature - hex signature of the monitored transaction * @param {string} address - signer's address * @returns {boolean} true if the signature is in the signer's pool */asyncfunctionisInUnconfirmedPool(signature,address){constpath=`/account/unconfirmedTransactions?address=${address}`;constresponse=awaitfetch(`${NODE_URL}${path}`);constpool=(awaitresponse.json()).data;consttarget=signature.toLowerCase();returnpool.some(entry=>entry.transaction.signature.toLowerCase()===target);}
defwait_for_confirmation(tx_hash,max_attempts=120,wait_seconds=1):""" Check for confirmation repeatedly until the transaction is confirmed or the attempts run out. Args: tx_hash: hash of the transaction to monitor max_attempts: maximum polling attempts wait_seconds: seconds to wait between attempts Returns: True if the transaction was confirmed, False otherwise """print("\nWaiting for transaction confirmation")forattemptinrange(1,max_attempts+1):time.sleep(wait_seconds)height=get_confirmation_height(tx_hash)status=f"confirmed in block {height}"ifheightelse"pending"print(f" Attempt {attempt}: {status}")ifheight:returnTruereturnFalse
/** * Check for confirmation repeatedly until the transaction is * confirmed or the attempts run out. * @param {string} txHash - hash of the transaction to monitor * @param {number} maxAttempts - maximum polling attempts * @param {number} waitSeconds - seconds to wait between attempts * @returns {boolean} true if the transaction was confirmed */asyncfunctionwaitForConfirmation(txHash,maxAttempts=120,waitSeconds=1){console.log('\nWaiting for transaction confirmation');for(letattempt=1;attempt<=maxAttempts;attempt++){awaitnewPromise(resolve=>{setTimeout(resolve,waitSeconds*1000);});constheight=awaitgetConfirmationHeight(txHash);conststatus=height?`confirmed in block ${height}`:'pending';console.log(` Attempt ${attempt}: ${status}`);if(height)returntrue;}returnfalse;}
try:block_height=get_confirmation_height(transaction_hash)ifblock_height:print(f"\nTransaction confirmed in block {block_height}")elifnotis_in_unconfirmed_pool(transaction_signature,signer_address):print("\nTransaction not found")elifwait_for_confirmation(transaction_hash):print("\nTransaction confirmed!")else:print("\nTransaction not confirmed within the polling window")excepturllib.error.URLErroraserr:print(f"\nCould not reach the node: {err.reason}")
try{constblockHeight=awaitgetConfirmationHeight(transactionHash);if(blockHeight)console.log(`\nTransaction confirmed in block ${blockHeight}`);elseif(!(awaitisInUnconfirmedPool(transactionSignature,signerAddress)))console.log('\nTransaction not found');elseif(awaitwaitForConfirmation(transactionHash))console.log('\nTransaction confirmed!');elseconsole.log('\nConfirmation timed out');}catch(error){console.log(`\nCould not reach the node: ${error.message}`);}