Asset references provide a unified and concise way to refer to a CoinSpark asset.

Once the transaction which created a CoinSpark asset has been confirmed on the bitcoin blockchain, that asset has a reference.

The asset reference contains three pieces of information:

  • blockNum – the number of the bitcoin block containing the transaction with genesis metadata which created the asset.
  • txOffset – the byte offset within that bitcoin block of the transaction which created the asset.
  • txIDPrefix – the first two bytes of the bitcoin txid of the transaction which created the asset. This serves as an extra check to ensure that blockchain substitutions don’t lead to ambiguity about the meaning of an asset reference.

If there is no bitcoin transaction which matches all of these pieces of information and contains genesis metadata, the asset reference is considered invalid.

Within the CoinSpark library, asset references are stored in a CoinSparkAssetRef structure or object, which is also embedded inside a CoinSparkTransfer. Asset references are used instead of the full txid of the genesis transaction for two reasons. First, they can be encoded much more efficiently, using between 8 and 10 bytes instead of 32. Considering that OP_RETURNs are currently limited to 40 bytes (as of Bitcoin Core 0.9), this optimization is essential to allow multiple asset types to be transferred in a single transaction. Second, they enable the transaction which created the asset to be retrieved from the bitcoin network by lightweight clients, using the block number. It would not be possible to do this with the txid because standard bitcoin nodes do not store a full index of transactions.

Asset references are also exposed to users if they want to manually add an asset type to their CoinSpark wallet. For user purposes they should be formatted as the concatenation of:

  1. The block number represented as an unsigned integer with no thousands separator.
  2. - (a regular hyphen)
  3. The byte offset represented as an unsigned integer with no thousands separator.
  4. - (a regular hyphen)
  5. The first two bytes of the txid converted to a unsigned integer with no thousands separator. The first byte of the txid is less significant, so the second is multiple by 256 to create the integer.

When formatted for users, asset references look a little like extended telephone numbers. For example, 456789-65432-23456 refers to the asset created by the transaction located at byte offset 65432 of bitcoin block 456789, whose txid begins with a05b.

You can easily convert asset references to and from strings using the appropriate CoinSpark library for your programming language.

Formatting an asset reference for users

C/C++

CoinSparkAssetRef assetRef;
char assetRefString[64];
size_t assetRefStringLen;

assetRef.blockNum=456789;
assetRef.txOffset=65432;
assetRef.txIDPrefix[0]=0xA0;
assetRef.txIDPrefix[1]=0x5B;

assetRefStringLen=CoinSparkAssetRefEncode(&assetRef, assetRefString, sizeof(assetRefString));

if (assetRefStringLen)
    printf("Asset reference: %s\n", assetRefString);
else
    printf("String passed was not long enough!\n");

Java

CoinSparkAssetRef assetRef=new CoinSparkAssetRef();

assetRef.setBlockNum(456789);
assetRef.setTxOffset(65432);
assetRef.setTxIDPrefix(new byte[] {(byte)0xa0, (byte)0x5b});

System.out.println("Asset reference: "+assetRef.encode());

Javascript

var assetRef=new CoinSparkAssetRef();

assetRef.blockNum=456789;
assetRef.txOffset=65432;
assetRef.txIDPrefix="a05b";

console.log("Asset reference: "+assetRef.encode());

PHP

$assetRef=new CoinSparkAssetRef();

$assetRef->blockNum=456789;
$assetRef->txOffset=65432;
$assetRef->txIDPrefix="a05b";

echo "Asset reference: ".$assetRef->encode()."\n";

Python

assetRef=CoinSparkAssetRef()

assetRef.blockNum=456789
assetRef.txOffset=65432
assetRef.txIDPrefix="a05b"

print("Asset reference: "+assetRef.encode())

Ruby

assetRef=CoinSparkAssetRef.new

assetRef.blockNum=456789
assetRef.txOffset=65432
assetRef.txIDPrefix="a05b"

puts("Asset reference: "+assetRef.encode)

Reading a user-provided asset reference

C/C++

char assetRefString[]="456789-65432-23456", debugString[1024];
CoinSparkAssetRef assetRef;

if (CoinSparkAssetRefDecode(&assetRef, assetRefString, strlen(assetRefString)) {
    printf("Block number: %ld\n", assetRef.blockNum);
    printf("Byte offset: %ld\n", assetRef.txOffset);
    printf("TxID prefix: %02x%02x\n", assetRef.txIDPrefix[0], assetRef.txIDPrefix[1]);

    CoinSparkAssetRefToString(&assetRef, debugString, sizeof(debugString));
    printf(debugString);

} else
    printf("Asset reference could not be read!\n");

Java

CoinSparkAssetRef assetRef=new CoinSparkAssetRef();

if (assetRef.decode("456789-65432-23456")) {
    System.out.println("Block number: "+assetRef.getBlockNum());
    System.out.println("Byte offset: "+assetRef.getTxOffset());
    System.out.println("TxID prefix: "+String.format("%02X%02X", assetRef.getTxIDPrefix()[0], assetRef.getTxIDPrefix()[1]));
    
    System.out.print(assetRef.toString());            

} else
    System.out.println("Asset reference could not be read!");                        

Javascript

var assetRef=new CoinSparkAssetRef();

if (assetRef.decode("456789-65432-23456")) {
    console.log("Block number: "+assetRef.blockNum);
    console.log("Byte offset: "+assetRef.txOffset);
    console.log("TxID prefix: "+assetRef.txIDPrefix);

    console.log(assetRef.toString());

} else
    console.log("Asset reference could not be read!");

PHP

$assetRef=new CoinSparkAssetRef();

if ($assetRef->decode("456789-65432-23456")) {
    echo "Block number: ".$assetRef->blockNum."\n"; 
    echo "Byte offset: ".$assetRef->txOffset."\n"; 
    echo "TxID prefix: ".$assetRef->txIDPrefix."\n"; 

    echo $assetRef->toString();

} else
    echo "Asset reference could not be read!\n";

Python

assetRef=CoinSparkAssetRef()

if assetRef.decode("456789-65432-23456"):
    print("Block number: "+str(assetRef.blockNum))
    print("Byte offset: "+str(assetRef.txOffset))
    print("TxID prefix: "+assetRef.txIDPrefix)

    sys.stdout.write(assetRef.toString())            

else:
    print("Asset reference could not be read!")                        

Ruby

assetRef=CoinSparkAssetRef.new

if assetRef.decode("456789-65432-23456")
    puts("Block number: "+assetRef.blockNum.to_s)
    puts("Byte offset: "+assetRef.txOffset.to_s)
    puts("TxID prefix: "+assetRef.txIDPrefix)

    print(assetRef.toString)
else
    puts("Asset reference could not be read!")
end