importhashlibimportjsonimportosimporturllib.requestfrombinasciiimportunhexlifyfromsymbolchain.BufferWriterimportBufferWriterfromsymbolchain.CryptoTypesimportHash256fromsymbolchain.symbol.Merkleimport(deserialize_patricia_tree_nodes,prove_patricia_merkle)NODE_URL=os.getenv('NODE_URL','https://reference.symboltest.net:3001')print(f'Using node {NODE_URL}')try:# Fetch the network currency mosaic IDurl=f'{NODE_URL}/network/properties'withurllib.request.urlopen(url)asresponse:props=json.loads(response.read().decode())raw_id=props['chain']['currencyMosaicId']mosaic_id=int(raw_id.replace('\'',''),16)mosaic_id_hex=f'{mosaic_id:016X}'print(f'Currency mosaic ID: {mosaic_id_hex}')# Fetch the mosaic propertiesmosaic_path=f'/mosaics/{mosaic_id_hex}'print(f'Fetching mosaic from {mosaic_path}')url=f'{NODE_URL}{mosaic_path}'withurllib.request.urlopen(url)asresponse:mosaic_data=json.loads(response.read().decode())mosaic=mosaic_data['mosaic']print(json.dumps(mosaic,indent=2))# Serialize and hash the mosaic propertieswriter=BufferWriter()writer.write_int(int(mosaic['version']),2)writer.write_int(int(mosaic['id'],16),8)writer.write_int(int(mosaic['supply']),8)writer.write_int(int(mosaic['startHeight']),8)writer.write_bytes(unhexlify(mosaic['ownerAddress']))writer.write_int(int(mosaic['revision']),4)writer.write_int(int(mosaic['flags']),1)writer.write_int(int(mosaic['divisibility']),1)writer.write_int(int(mosaic['duration']),8)hashed_value=Hash256(hashlib.sha3_256(writer.buffer).digest())print(f'Hashed value: {hashed_value}')# Hash the mosaic ID to get the encoded keywriter=BufferWriter()writer.write_int(int(mosaic['id'],16),8)encoded_key=Hash256(hashlib.sha3_256(writer.buffer).digest())print(f'Encoded key: {encoded_key}')# Fetch the current network heighturl=f'{NODE_URL}/chain/info'withurllib.request.urlopen(url)asresponse:chain_info=json.loads(response.read().decode())height=int(chain_info['height'])print(f'Current height: {height}')# Fetch the block's state hash and rootsblock_path=f'/blocks/{height}'print(f'Fetching block from {block_path}')url=f'{NODE_URL}{block_path}'withurllib.request.urlopen(url)asresponse:block_data=json.loads(response.read().decode())state_hash=Hash256(block_data['block']['stateHash'])sub_cache_key='stateHashSubCacheMerkleRoots'roots=[Hash256(r)forrinblock_data['meta'][sub_cache_key]]print(f'State hash: {state_hash}')# Fetch the patricia tree pathtree_url=f'/mosaics/{mosaic_id_hex}/merkle'print(f'Fetching tree path from {tree_url}')url=f'{NODE_URL}{tree_url}'withurllib.request.urlopen(url)asresponse:tree_data=json.loads(response.read().decode())merkle_path=deserialize_patricia_tree_nodes(unhexlify(tree_data['raw']))print(f'Tree path: {len(merkle_path)} nodes')key_hex=str(encoded_key)key_pos=0fori,nodeinenumerate(merkle_path):key_pos+=node.path.sizepath_str=(f' path: {node.hex_path}'ifnode.path.sizeelse'')ifhasattr(node,'value'):print(f' [{i}] leaf{path_str} value: {node.value}')else:nibble=key_hex[key_pos]key_pos+=1active=[f'{j:X}'forj,linkinenumerate(node.links)iflink]print(f' [{i}] branch{path_str}'f" links: [{','.join(active)}]"f' -> follow {nibble}')# Verify the mosaic stateresult=prove_patricia_merkle(encoded_key,hashed_value,merkle_path,state_hash,roots)ifresult.name=='VALID_POSITIVE':print(f'Mosaic {mosaic_id_hex} state verified at height {height}')else:raiseRuntimeError(f'Mosaic {mosaic_id_hex} proof failed: {result.name}')exceptExceptionase:print(e)
import{Hash256,utils}from'symbol-sdk';import{deserializePatriciaTreeNodes,provePatriciaMerkle}from'symbol-sdk/symbol';importcryptofrom'crypto';const{hexToUint8,intToBytes}=utils;constNODE_URL=process.env.NODE_URL||'https://reference.symboltest.net:3001';console.log('Using node',NODE_URL);constsha3_256=data=>crypto.createHash('sha3-256').update(data).digest();constconcat=(...arrays)=>{consttotal=arrays.reduce((n,a)=>n+a.length,0);constbuf=newUint8Array(total);letoff=0;for(constaofarrays){buf.set(a,off);off+=a.length;}returnbuf;};try{// Fetch the network currency mosaic IDconstpropsRes=awaitfetch(`${NODE_URL}/network/properties`);constprops=awaitpropsRes.json();constrawId=props.chain.currencyMosaicId;constmosaicId=BigInt(rawId.replaceAll('\'',''));constmosaicIdHex=mosaicId.toString(16).toUpperCase().padStart(16,'0');console.log('Currency mosaic ID:',mosaicIdHex);// Fetch the mosaic propertiesconstmosaicPath=`/mosaics/${mosaicIdHex}`;console.log('Fetching mosaic from',mosaicPath);constmosaicRes=awaitfetch(`${NODE_URL}${mosaicPath}`);constmosaicData=awaitmosaicRes.json();constmosaic=mosaicData.mosaic;console.log(JSON.stringify(mosaic,undefined,2));// Serialize and hash the mosaic propertiesconstserialized=concat(intToBytes(parseInt(mosaic.version,10),2),intToBytes(BigInt(`0x${mosaic.id}`),8),intToBytes(BigInt(mosaic.supply),8),intToBytes(BigInt(mosaic.startHeight),8),hexToUint8(mosaic.ownerAddress),intToBytes(parseInt(mosaic.revision,10),4),intToBytes(parseInt(mosaic.flags,10),1),intToBytes(parseInt(mosaic.divisibility,10),1),intToBytes(BigInt(mosaic.duration),8));consthashedValue=newHash256(sha3_256(serialized));console.log('Hashed value:',hashedValue.toString());// Hash the mosaic ID to get the encoded keyconstkeyBytes=intToBytes(BigInt(`0x${mosaic.id}`),8);constencodedKey=newHash256(sha3_256(keyBytes));console.log('Encoded key:',encodedKey.toString());// Fetch the current network heightconstchainRes=awaitfetch(`${NODE_URL}/chain/info`);constchainInfo=awaitchainRes.json();constheight=BigInt(chainInfo.height);console.log(`Current height: ${height}`);// Fetch the block's state hash and rootsconstblockPath=`/blocks/${height}`;console.log('Fetching block from',blockPath);constblockRes=awaitfetch(`${NODE_URL}${blockPath}`);constblockData=awaitblockRes.json();conststateHash=newHash256(blockData.block.stateHash);constroots=blockData.meta.stateHashSubCacheMerkleRoots.map(r=>newHash256(r));console.log('State hash:',stateHash.toString());// Fetch the patricia tree pathconsttreeUrl=`/mosaics/${mosaicIdHex}/merkle`;console.log('Fetching tree path from',treeUrl);consttreeRes=awaitfetch(`${NODE_URL}${treeUrl}`);consttreeData=awaittreeRes.json();constmerklePath=deserializePatriciaTreeNodes(hexToUint8(treeData.raw));console.log('Tree path:',merklePath.length,'nodes');constkeyHex=encodedKey.toString();letkeyPos=0;merklePath.forEach((node,i)=>{keyPos+=node.path.size;constpathStr=node.path.size?` path: ${node.hexPath}`:'';if('value'innode){console.log(` [${i}] leaf${pathStr} value: ${node.value}`);}else{constnibble=keyHex[keyPos];keyPos+=1;constactive=node.links.map((l,j)=>(l?j.toString(16).toUpperCase():null)).filter(x=>null!==x);console.log(` [${i}] branch${pathStr}`+` links: [${active}]`+` -> follow ${nibble}`);}});// Verify the mosaic stateconstresult=provePatriciaMerkle(encodedKey,hashedValue,merklePath,stateHash,roots);if(0x0001===result){// VALID_POSITIVEconsole.log(`Mosaic ${mosaicIdHex} state verified at height ${height}`);}else{thrownewError(`Mosaic ${mosaicIdHex} proof failed: ${result}`);}}catch(e){console.error(e.message);}
//JAVA 21+//DEPS org.symbol:symbol-sdk:3.3.1importjava.io.IOException;importjava.net.URI;importjava.net.http.HttpClient;importjava.net.http.HttpRequest;importjava.net.http.HttpResponse;importjava.net.http.HttpResponse.BodyHandlers;importjava.nio.ByteBuffer;importjava.nio.ByteOrder;importjava.util.ArrayList;importjava.util.List;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.symbol.sdk.CryptoTypes;importorg.symbol.sdk.symbol.Merkle;importorg.symbol.sdk.symbol.Merkle.BranchNode;importorg.symbol.sdk.symbol.Merkle.LeafNode;importorg.symbol.sdk.symbol.Merkle.PatriciaMerkleProofResult;importorg.symbol.sdk.symbol.Merkle.TreeNode;importorg.symbol.sdk.utils.Converter;importorg.symbol.sdk.utils.Transforms;publicfinalclassProveMosaicDefinition{privatestaticfinalObjectMapperJSON_MAPPER=newObjectMapper();privatestaticfinalHttpClientHTTP_CLIENT=HttpClient.newHttpClient();privatefinalStringnodeUrl=System.getenv().getOrDefault("NODE_URL","https://reference.symboltest.net:3001");publicstaticvoidmain(finalString[]args){try{newProveMosaicDefinition().run();}catch(finalExceptionex){System.out.println(null==ex.getMessage()?ex.toString():ex.getMessage());}}privatevoidrun()throwsIOException,InterruptedException{System.out.printf("Using node %s%n",nodeUrl);// Fetch the network currency mosaic IDfinalJsonNodeprops=getJson("/network/properties");finalStringrawId=props.get("chain").get("currencyMosaicId").asText();finallongmosaicId=Long.parseUnsignedLong(rawId.substring(2).replace("'",""),16);finalStringmosaicIdHex="%016X".formatted(mosaicId);System.out.printf("Currency mosaic ID: %s%n",mosaicIdHex);// Fetch the mosaic propertiesfinalStringmosaicPath="/mosaics/"+mosaicIdHex;System.out.printf("Fetching mosaic from %s%n",mosaicPath);finalJsonNodemosaicData=getJson(mosaicPath);finalJsonNodemosaic=mosaicData.get("mosaic");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(mosaic));// Serialize and hash the mosaic propertiesfinalByteBufferbuffer=ByteBuffer.allocate(40+24).order(ByteOrder.LITTLE_ENDIAN);buffer.putShort((short)mosaic.get("version").asInt());buffer.putLong(Long.parseUnsignedLong(mosaic.get("id").asText(),16));buffer.putLong(Long.parseUnsignedLong(mosaic.get("supply").asText()));buffer.putLong(Long.parseUnsignedLong(mosaic.get("startHeight").asText()));buffer.put(Converter.hexToUint8(mosaic.get("ownerAddress").asText()));buffer.putInt(mosaic.get("revision").asInt());buffer.put((byte)mosaic.get("flags").asInt());buffer.put((byte)mosaic.get("divisibility").asInt());buffer.putLong(Long.parseUnsignedLong(mosaic.get("duration").asText()));finalCryptoTypes.Hash256hashedValue=newCryptoTypes.Hash256(Transforms.sha3_256(buffer.array()));System.out.printf("Hashed value: %s%n",hashedValue);// Hash the mosaic ID to get the encoded keyfinalByteBufferkeyBuffer=ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);keyBuffer.putLong(Long.parseUnsignedLong(mosaic.get("id").asText(),16));finalCryptoTypes.Hash256encodedKey=newCryptoTypes.Hash256(Transforms.sha3_256(keyBuffer.array()));System.out.printf("Encoded key: %s%n",encodedKey);// Fetch the current network heightfinalJsonNodechainInfo=getJson("/chain/info");finallongheight=chainInfo.get("height").asLong();System.out.printf("Current height: %d%n",height);// Fetch the block's state hash and rootsfinalStringblockPath="/blocks/"+height;System.out.printf("Fetching block from %s%n",blockPath);finalJsonNodeblockData=getJson(blockPath);finalCryptoTypes.Hash256stateHash=newCryptoTypes.Hash256(blockData.get("block").get("stateHash").asText());finalList<CryptoTypes.Hash256>roots=newArrayList<>();for(finalJsonNoderoot:blockData.get("meta").get("stateHashSubCacheMerkleRoots"))roots.add(newCryptoTypes.Hash256(root.asText()));System.out.printf("State hash: %s%n",stateHash);// Fetch the patricia tree pathfinalStringtreeUrl="/mosaics/"+mosaicIdHex+"/merkle";System.out.printf("Fetching tree path from %s%n",treeUrl);finalJsonNodetreeData=getJson(treeUrl);finalList<TreeNode>merklePath=Merkle.deserializePatriciaTreeNodes(Converter.hexToUint8(treeData.get("raw").asText()));System.out.printf("Tree path: %d nodes%n",merklePath.size());finalStringkeyHex=encodedKey.toString();intkeyPos=0;for(inti=0;merklePath.size()>i;++i){finalTreeNodenode=merklePath.get(i);keyPos+=node.path.size();finalStringpathStr=0!=node.path.size()?" path: "+node.hexPath():"";if(nodeinstanceofLeafNodeleaf){System.out.printf(" [%d] leaf%s value: %s%n",i,pathStr,leaf.value);}elseif(nodeinstanceofBranchNodebranch){finalcharnibble=keyHex.charAt(keyPos);++keyPos;finalList<String>active=newArrayList<>();for(intj=0;branch.links.length>j;++j){if(null!=branch.links[j])active.add("%X".formatted(j));}System.out.printf(" [%d] branch%s links: [%s] -> follow %c%n",i,pathStr,String.join(",",active),nibble);}}// Verify the mosaic statefinalintresult=Merkle.provePatriciaMerkle(encodedKey,hashedValue,merklePath,stateHash,roots);if(PatriciaMerkleProofResult.VALID_POSITIVE==result){System.out.printf("Mosaic %s state verified at height %d%n",mosaicIdHex,height);}else{thrownewIllegalStateException(String.format("Mosaic %s proof failed: %d",mosaicIdHex,result));}}privateJsonNodegetJson(finalStringpath)throwsIOException,InterruptedException{finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());returnJSON_MAPPER.readTree(response.body());}}
# Serialize and hash the mosaic propertieswriter=BufferWriter()writer.write_int(int(mosaic['version']),2)writer.write_int(int(mosaic['id'],16),8)writer.write_int(int(mosaic['supply']),8)writer.write_int(int(mosaic['startHeight']),8)writer.write_bytes(unhexlify(mosaic['ownerAddress']))writer.write_int(int(mosaic['revision']),4)writer.write_int(int(mosaic['flags']),1)writer.write_int(int(mosaic['divisibility']),1)writer.write_int(int(mosaic['duration']),8)hashed_value=Hash256(hashlib.sha3_256(writer.buffer).digest())print(f'Hashed value: {hashed_value}')# Hash the mosaic ID to get the encoded keywriter=BufferWriter()writer.write_int(int(mosaic['id'],16),8)encoded_key=Hash256(hashlib.sha3_256(writer.buffer).digest())print(f'Encoded key: {encoded_key}')
// Serialize and hash the mosaic propertiesconstserialized=concat(intToBytes(parseInt(mosaic.version,10),2),intToBytes(BigInt(`0x${mosaic.id}`),8),intToBytes(BigInt(mosaic.supply),8),intToBytes(BigInt(mosaic.startHeight),8),hexToUint8(mosaic.ownerAddress),intToBytes(parseInt(mosaic.revision,10),4),intToBytes(parseInt(mosaic.flags,10),1),intToBytes(parseInt(mosaic.divisibility,10),1),intToBytes(BigInt(mosaic.duration),8));consthashedValue=newHash256(sha3_256(serialized));console.log('Hashed value:',hashedValue.toString());// Hash the mosaic ID to get the encoded keyconstkeyBytes=intToBytes(BigInt(`0x${mosaic.id}`),8);constencodedKey=newHash256(sha3_256(keyBytes));console.log('Encoded key:',encodedKey.toString());
// Serialize and hash the mosaic propertiesfinalByteBufferbuffer=ByteBuffer.allocate(40+24).order(ByteOrder.LITTLE_ENDIAN);buffer.putShort((short)mosaic.get("version").asInt());buffer.putLong(Long.parseUnsignedLong(mosaic.get("id").asText(),16));buffer.putLong(Long.parseUnsignedLong(mosaic.get("supply").asText()));buffer.putLong(Long.parseUnsignedLong(mosaic.get("startHeight").asText()));buffer.put(Converter.hexToUint8(mosaic.get("ownerAddress").asText()));buffer.putInt(mosaic.get("revision").asInt());buffer.put((byte)mosaic.get("flags").asInt());buffer.put((byte)mosaic.get("divisibility").asInt());buffer.putLong(Long.parseUnsignedLong(mosaic.get("duration").asText()));finalCryptoTypes.Hash256hashedValue=newCryptoTypes.Hash256(Transforms.sha3_256(buffer.array()));System.out.printf("Hashed value: %s%n",hashedValue);// Hash the mosaic ID to get the encoded keyfinalByteBufferkeyBuffer=ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);keyBuffer.putLong(Long.parseUnsignedLong(mosaic.get("id").asText(),16));finalCryptoTypes.Hash256encodedKey=newCryptoTypes.Hash256(Transforms.sha3_256(keyBuffer.array()));System.out.printf("Encoded key: %s%n",encodedKey);
# Fetch the current network heighturl=f'{NODE_URL}/chain/info'withurllib.request.urlopen(url)asresponse:chain_info=json.loads(response.read().decode())height=int(chain_info['height'])print(f'Current height: {height}')# Fetch the block's state hash and rootsblock_path=f'/blocks/{height}'print(f'Fetching block from {block_path}')url=f'{NODE_URL}{block_path}'withurllib.request.urlopen(url)asresponse:block_data=json.loads(response.read().decode())state_hash=Hash256(block_data['block']['stateHash'])sub_cache_key='stateHashSubCacheMerkleRoots'roots=[Hash256(r)forrinblock_data['meta'][sub_cache_key]]print(f'State hash: {state_hash}')
// Fetch the current network heightconstchainRes=awaitfetch(`${NODE_URL}/chain/info`);constchainInfo=awaitchainRes.json();constheight=BigInt(chainInfo.height);console.log(`Current height: ${height}`);// Fetch the block's state hash and rootsconstblockPath=`/blocks/${height}`;console.log('Fetching block from',blockPath);constblockRes=awaitfetch(`${NODE_URL}${blockPath}`);constblockData=awaitblockRes.json();conststateHash=newHash256(blockData.block.stateHash);constroots=blockData.meta.stateHashSubCacheMerkleRoots.map(r=>newHash256(r));console.log('State hash:',stateHash.toString());
// Fetch the current network heightfinalJsonNodechainInfo=getJson("/chain/info");finallongheight=chainInfo.get("height").asLong();System.out.printf("Current height: %d%n",height);// Fetch the block's state hash and rootsfinalStringblockPath="/blocks/"+height;System.out.printf("Fetching block from %s%n",blockPath);finalJsonNodeblockData=getJson(blockPath);finalCryptoTypes.Hash256stateHash=newCryptoTypes.Hash256(blockData.get("block").get("stateHash").asText());finalList<CryptoTypes.Hash256>roots=newArrayList<>();for(finalJsonNoderoot:blockData.get("meta").get("stateHashSubCacheMerkleRoots"))roots.add(newCryptoTypes.Hash256(root.asText()));System.out.printf("State hash: %s%n",stateHash);
# Verify the mosaic stateresult=prove_patricia_merkle(encoded_key,hashed_value,merkle_path,state_hash,roots)ifresult.name=='VALID_POSITIVE':print(f'Mosaic {mosaic_id_hex} state verified at height {height}')else:raiseRuntimeError(f'Mosaic {mosaic_id_hex} proof failed: {result.name}')
// Verify the mosaic statefinalintresult=Merkle.provePatriciaMerkle(encodedKey,hashedValue,merklePath,stateHash,roots);if(PatriciaMerkleProofResult.VALID_POSITIVE==result){System.out.printf("Mosaic %s state verified at height %d%n",mosaicIdHex,height);}else{thrownewIllegalStateException(String.format("Mosaic %s proof failed: %d",mosaicIdHex,result));}