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")exceptExceptionaserror:print(f"\nCould not reach the node: {error}")
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}`);}
//JAVA 21+//DEPS org.symbol:symbol-sdk:3.3.3importjava.io.IOException;importjava.net.URI;importjava.net.http.HttpClient;importjava.net.http.HttpRequest;importjava.net.http.HttpResponse;importjava.net.http.HttpResponse.BodyHandlers;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;publicfinalclassMonitoringStatus{privatestaticfinalObjectMapperJSON_MAPPER=newObjectMapper();privatestaticfinalHttpClientHTTP_CLIENT=HttpClient.newHttpClient();privatestaticfinalStringNODE_URL=System.getenv().getOrDefault("NODE_URL","http://libertalia.nemtest.net:7890");// Query /transaction/get once to check for confirmation.privatestaticLonggetConfirmationHeight(finalStringtransactionHash)throwsIOException,InterruptedException{finalStringpath=String.format("/transaction/get?hash=%s",transactionHash);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(NODE_URL+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());if(2==response.statusCode()/100)returnJSON_MAPPER.readTree(response.body()).get("meta").get("height").asLong();if(400!=response.statusCode())thrownewIOException("Unexpected status: "+response.statusCode());returnnull;}// Check whether a transaction is in the address's unconfirmed pool.privatestaticbooleanisInUnconfirmedPool(finalStringsignature,finalStringaddress)throwsIOException,InterruptedException{finalStringpath=String.format("/account/unconfirmedTransactions?address=%s",address);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(NODE_URL+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());finalJsonNodepool=JSON_MAPPER.readTree(response.body()).get("data");for(finalJsonNodeentry:pool){finalStringcandidate=entry.get("transaction").get("signature").asText();if(signature.equalsIgnoreCase(candidate))returntrue;}returnfalse;}// Check repeatedly until the transaction is confirmed.privatestaticbooleanwaitForConfirmation(finalStringtransactionHash,finalintmaxAttempts,finalintwaitSeconds)throwsIOException,InterruptedException{System.out.println("\nWaiting for transaction confirmation");for(intattempt=1;maxAttempts>=attempt;++attempt){Thread.sleep(waitSeconds*1000L);finalLongheight=getConfirmationHeight(transactionHash);finalStringstatus=null==height?"pending":"confirmed in block "+height;System.out.printf(" Attempt %d: %s%n",attempt,status);if(null!=height)returntrue;}returnfalse;}publicstaticvoidmain(finalString[]args){try{newMonitoringStatus().run();}catch(finalExceptionex){System.out.println(null==ex.getMessage()?ex.toString():ex.getMessage());}}privatevoidrun()throwsIOException,InterruptedException{System.out.printf("Using node %s%n",NODE_URL);// Transaction hash to monitor.finalStringtransactionHash=System.getenv().getOrDefault("TRANSACTION_HASH","AE0B2142DFB75C9C126442EF612944E926BCE63FA34B353CDE409E2E87703"+"C0B");// Signer's address.finalStringsignerAddress=System.getenv().getOrDefault("SIGNER_ADDRESS","TBONKWCOWBZYZB2I5JD3LSDBQVBYHB757VN3SKPP");// Transaction signature.finalStringtransactionSignature=System.getenv().getOrDefault("TRANSACTION_SIGNATURE","99B1850FADDB964112D030AA0A5C9F8B5B1B6B992B407D9C70"+"F52F089BD651DFA7D4991639A48B810EFD98C45060D7AD9AE5"+"7FDA37F58561459DCE8D0A747F02");System.out.printf("Monitoring transaction: %s%n",transactionHash);finalLongblockHeight=getConfirmationHeight(transactionHash);if(null!=blockHeight)System.out.printf("%nTransaction confirmed in block %d%n",blockHeight);elseif(!isInUnconfirmedPool(transactionSignature,signerAddress))System.out.println("\nTransaction not found");elseif(waitForConfirmation(transactionHash,120,1))System.out.println("\nTransaction confirmed!");elseSystem.out.println("\nConfirmation timed out");}}
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;}
// Query /transaction/get once to check for confirmation.privatestaticLonggetConfirmationHeight(finalStringtransactionHash)throwsIOException,InterruptedException{finalStringpath=String.format("/transaction/get?hash=%s",transactionHash);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(NODE_URL+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());if(2==response.statusCode()/100)returnJSON_MAPPER.readTree(response.body()).get("meta").get("height").asLong();if(400!=response.statusCode())thrownewIOException("Unexpected status: "+response.statusCode());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);}
// Check whether a transaction is in the address's unconfirmed pool.privatestaticbooleanisInUnconfirmedPool(finalStringsignature,finalStringaddress)throwsIOException,InterruptedException{finalStringpath=String.format("/account/unconfirmedTransactions?address=%s",address);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(NODE_URL+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());finalJsonNodepool=JSON_MAPPER.readTree(response.body()).get("data");for(finalJsonNodeentry:pool){finalStringcandidate=entry.get("transaction").get("signature").asText();if(signature.equalsIgnoreCase(candidate))returntrue;}returnfalse;}
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;}
// Check repeatedly until the transaction is confirmed.privatestaticbooleanwaitForConfirmation(finalStringtransactionHash,finalintmaxAttempts,finalintwaitSeconds)throwsIOException,InterruptedException{System.out.println("\nWaiting for transaction confirmation");for(intattempt=1;maxAttempts>=attempt;++attempt){Thread.sleep(waitSeconds*1000L);finalLongheight=getConfirmationHeight(transactionHash);finalStringstatus=null==height?"pending":"confirmed in block "+height;System.out.printf(" Attempt %d: %s%n",attempt,status);if(null!=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")exceptExceptionaserror:print(f"\nCould not reach the node: {error}")
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}`);}
finalLongblockHeight=getConfirmationHeight(transactionHash);if(null!=blockHeight)System.out.printf("%nTransaction confirmed in block %d%n",blockHeight);elseif(!isInUnconfirmedPool(transactionSignature,signerAddress))System.out.println("\nTransaction not found");elseif(waitForConfirmation(transactionHash,120,1))System.out.println("\nTransaction confirmed!");elseSystem.out.println("\nConfirmation timed out");