Transactions

Similarly to a database, a transaction is a group of operations on funds that satisfies the ACID properties. The operations in a transaction will all occur or none will (atomicity), only transactions that are valid spends are allowed (consistency), blocks serialise transactions for concurrency control (isolation) and the consensus algorithm provides protection from transaction reversals (durability).

The essential building blocks of a transaction are inputs and outputs. An output is a store of coins along with rules about how those coins can be spent as well as arbitrary data that can be included with the output. An input spends an output by providing whatever data is required to spend the output by the rules specified in the output. A transaction is a set of inputs spending existing unspent outputs and a set of new outputs that will be created if the transaction is included in the blockchain. The total value of the new outputs in a transaction is less than the total value of the outputs being spent by the inputs. The deficit between these two values is the fee that is charged for the transaction. Every transaction has at least one inputs except for coinbase transactions which are created as a part of blocks and are the means by which new coins are added to the system. Every input spends its output in its entirety so any coins that you do not want to be given away as a fee must be re-allocated as new outputs in the transaction.

Your first transaction

The remainder of this tutorial assumes you already have some K320 to use (or that you know how to bootstrap your own test coin). Check the quickstart guide for details on how to mine K320 to use for testing. We are going to use Python 3 to interface with Cryptokernel and build transactions. Make sure Python 3 is intalled on your system and that you have ckd configured and running before continuing.

Communicating with ckd via JSON-RPC

First we must get your Python code communicating with ckd. The prefered method for this is JSON-RPC. The RPC endpoint is password protected so we must write a Python function that is able to make an authenticated request to ckd. Check your config.json file and make a note of the rpcuser and rpcpassword fields as we will use these to connect to ckd.

Then add to a Python script the following request function:

import requests
import json
import base64

url = "http://localhost:8383"
rpcuser = "ckrpc"
rpcpassword = "password"

def request(method, params):
    unencoded_str = rpcuser + ":" + rpcpassword 
    encoded_str = base64.b64encode(unencoded_str.encode())
    headers = {
        "content-type": "application/json",
        "Authorization": "Basic " + encoded_str.decode('utf-8')}
    payload = {
        "method": method,
        "params": params,
        "jsonrpc": "2.0",
        "id": 0,
    }
    response = requests.post(url, data=json.dumps(payload), headers=headers).json()  
    return response

Replace the rpcuser and rpcpassword variables with the values copied from your config.json file. If you are using a coin other than K320 you will need to change the url variable to reflect the port of the RPC endpoint for that coin.

Now we can make a simple RPC call to ckd:

...
res = request("getinfo", {})["result"]
print(res)
~$ python3 run.py
{'connections': 5, 'balance': '4266.12331762', 'mempool': {'count': 0, 'size': '0.000 MB'}, 'height': 209999, 'rpc_version': '0.0.2', 'ck_version': '0.2.0-alpha-dev'}

Retrieving unspent outputs

Now that we can communicate with ckd we can build, sign and broadcast transactions. To retrieve a list of unspent outputs from the wallet that can be spent in our transaction we can use the listunspentoutputs RPC call. listunspentoutputs takes as parameters the name of the wallet account to retrieve outputs for and your wallet password.

e.g.

params = {"account": "my_testing_account", "password": "mypassword"}

res = request("listunspentoutputs", params)["result"]
print(res)
~$ python3 run.py
{'outputs': [{'creationTx': '13fa025fff035176ca64ab3232e4ac138be14f5809f2e05f24d371af3602701a', 'data': {'publicKey': 'BNhtisPytzKtucZww4lA5mxgZG1qrd4vOBx8DJ7niFX8it3Jub7V2WG7Tc7WAg/SuTDYA7OJ624kfkb83Yg3hT8=', 'contract': None}, 'value': 7633425214, 'nonce': 631800362, 'id': '4fb5e6cf18b547a79b4ff7b8e9b1237df1f3091d93a8b96aa601ef0926132a0'}, {'creationTx': '9d4afb688205cf17debd29cfd1daf55ec3c8fa77cabd31dd1e63b357159818f1', 'data': {'publicKey': 'BNhtisPytzKtucZww4lA5mxgZG1qrd4vOBx8DJ7niFX8it3Jub7V2WG7Tc7WAg/SuTDYA7OJ624kfkb83Yg3hT8=', 'contract': None}
...

Anatomy of an output

Let’s take a look at one of these outputs and take a moment to understand what each of the fields mean.

params = {"account": "my_testing_account", "password": "mypassword"}

res = request("listunspentoutputs", params)["result"]
print(json.dumps(res["outputs"][0], sort_keys=True, indent=4))
~$ python3 run.py
{
    "creationTx": "13fa025fff035176ca64ab3232e4ac138be14f5809f2e05f24d371af3602701a",
    "data": {
        "contract": null,
        "publicKey": "BNhtisPytzKtucZww4lA5mxgZG1qrd4vOBx8DJ7niFX8it3Jub7V2WG7Tc7WAg/SuTDYA7OJ624kfkb83Yg3hT8="
    },
    "id": "4fb5e6cf18b547a79b4ff7b8e9b1237df1f3091d93a8b96aa601ef0926132a0",
    "nonce": 631800362,
    "value": 7633425214
}

The output as displayed above is almost as it appears as part of the Cryptokernel protocol except for the id and creationTx fields which are added by the RPC call for our convenience and not actually stored as part of the output. The id field displays the unique identifier for the output. Each output get its own ID and duplicates are not allowed. The creationTx field displayed the ID of the transaction which first created the output. The value field is an integer representing the number of coins stored in this output. This is the maximum number of coins that can be created as new outputs in a transaction if this input is spent. The data field contains arbitrary JSON used to specify rules about how the output can be spent. In this case there is a publicKey specified meaning that the spending input must contain a valid signature for the given public key. The nonce field is there in case you need to create outputs that would otherwise have colliding IDs and has no semantic meaning beyond changing the output ID.

We can use the gettransaction RPC call to retrieve the entire transaction including this output:

res = request("gettransaction", {"id": "13fa025fff035176ca64ab3232e4ac138be14f5809f2e05f24d371af3602701a"})["result"]
print(json.dumps(res, sort_keys=True, indent=4))
~$ python3 run.py
{
    "outputs": [
        {
            "data": {
                "contract": null,
                "publicKey": "BNhtisPytzKtucZww4lA5mxgZG1qrd4vOBx8DJ7niFX8it3Jub7V2WG7Tc7WAg/SuTDYA7OJ624kfkb83Yg3hT8="
            },
            "nonce": 631800362,
            "value": 7633425214
        }
    ],
    "timestamp": 1534331998
}

Here we can see the transaction was a coinbase transaction because there are no inputs and thus these coins were created as part of block production. If you mined K320 to acquire coins for part of this tutorial it’s likely your outputs will look similar to this one.

Constructing the transaction

We are going to create a transaction that will look very similar to one created by the sendtoaddress RPC call that’s covered in the quickstart guide. The transaction will spend one of the outputs retrieved in the previous section and create a new output that can be spent with a signature for the public key we provide, exactly the same as in sendtoaddress. First you will need to create a new account in the ckd wallet to get a new public key to send the funds to. Check the quickstart guide if you are unsure how to do that.

import time
...

...
params = {"account": "my_testing_account", "password": "mypassword"}

# retrieve an output to spend
toSpend = request("listunspentoutputs", params)["result"]["outputs"][0]

fee = 20000
publicKey = "BANyQ50v/jWXz4dKpeXclE21aTgDJhmIgCCNH7sxAzuZqfSx6im19iqZjWRHlbrWh2dQC++aixYT+60a+kq9+Rg="

# input wrapper spending output
input = {"outputId": toSpend["id"]}

# new output for spent funds (minus fee)
newOutput = {"value": toSpend["value"] - fee, 
             "nonce": 0, 
             "data": {"publicKey": publicKey}}

# the unsigned transaction
transaction = {"inputs": [input], "outputs": [newOutput], "timestamp": int(time.time())}

print(json.dumps(transaction, sort_keys=True, indent=4))
~$ python3 run.py
{
    "inputs": [
        {
            "outputId": "4fb5e6cf18b547a79b4ff7b8e9b1237df1f3091d93a8b96aa601ef0926132a0"
        }
    ],
    "outputs": [
        {
            "data": {
                "publicKey": "BANyQ50v/jWXz4dKpeXclE21aTgDJhmIgCCNH7sxAzuZqfSx6im19iqZjWRHlbrWh2dQC++aixYT+60a+kq9+Rg="
            },
            "nonce": 0,
            "value": 7633405214
        }
    ],
    "timestamp": 1534787996
}

The above code retrieves an unspent output and constructs an input from it by referencing the output’s ID in the outputId field. It then constructs a new output with the value of the output being spent minus a fee and the public key that is able to spend the new output. Finally it bundles the input and output into a transaction object and prints the result. The type of output we have created here is known as a pay-to-public-key output. The transaction is almost ready to send but it is missing a signature in the input which is required to spend the output.

Signing the transaction

ckd comes with a signtransaction RPC which understands how to sign inputs for outputs of the form used in this tutorial: where there is a publicKey field and no contract, and the private key for the public key is stored in the ckd wallet. This streamlines the process of signing common transactions as the use of additional cryptography libraries for Python is not required.

To sign our transaction:

...
signed = request("signtransaction", {"transaction": transaction, "password": "mypassword"})["result"]
print(json.dumps(signed, sort_keys=True, indent=4))
~$ python3 run.py
{
    "inputs": [
        {
            "data": {
                "signature": "MEUCIQC4T2cNiKWTuBYfULu7GEcQdN//+PcS4W9Gm+H/yWd2CgIgW+HVDq9MZbBDjTx9F6UJZzVS877bBadJgfVrjFXLkm0="
            },
            "outputId": "4fb5e6cf18b547a79b4ff7b8e9b1237df1f3091d93a8b96aa601ef0926132a0"
        }
    ],
    "outputs": [
        {
            "data": {
                "contract": null,
                "publicKey": "BANyQ50v/jWXz4dKpeXclE21aTgDJhmIgCCNH7sxAzuZqfSx6im19iqZjWRHlbrWh2dQC++aixYT+60a+kq9+Rg="
            },
            "nonce": 0,
            "value": 7633405214
        }
    ],
    "timestamp": 1534791303
}

The unsigned transaction from the previous section now has an additional data field in the input which contains the signature required to spend the given output. ckd analysed the transaction, found the corresponding private key for the public key in the output being spent, signed the transaction and inserted the signature.

Broadcasting the transaction

Now the transaction is complete and ready to be broadcast using the sendrawtransaction RPC.

...
success = request("sendrawtransaction", {"transaction": signed})["result"]
print(success)

If the transaction was accepted, checking getinfo should show a transaction in the memory pool of unconfirmed transactions:

~$ ./ckd getinfo
{
	"balance" : "4266.12331762",
	"ck_version" : "0.2.0-alpha-dev",
	"connections" : 4,
	"height" : 210079,
	"mempool" : 
	{
		"count" : 1,
		"size" : "0.000 MB"
	},
	"rpc_version" : "0.0.2"
}

Eventually, once the transaction is included in a block, the coins will appear as a balance in the account whose receiving address you used to create the new output:

~$ ./ckd account my_receiving_account
Please enter your wallet passphrase: ********
{
	"balance" : "76.334052",
	"keys" : 
	[
		{
			"privKey" : 
			{
				"cipherText" : "V3JamOeQdngOeZ1QaV5Vdndku1/kyCwLiY0CbEkZA23Q/eZBvI1xs1fy284Qb1su",
				"iv" : "/xo7J5HguwqdbqmrOzWwzA==",
				"salt" : "fRAeQvcFkgV5Vuz6F6cpWsQuvmMcmObypJAjQBnd0Bk="
			},
			"pubKey" : "BANyQ50v/jWXz4dKpeXclE21aTgDJhmIgCCNH7sxAzuZqfSx6im19iqZjWRHlbrWh2dQC++aixYT+60a+kq9+Rg="
		}
	],
	"name" : "my_receiving_account"
}

The complete code

import requests
import json
import base64
import time

url = "http://localhost:8383"
rpcuser = "ckrpc"
rpcpassword = "ckpassword"
walletpassword = "mypassword"
walletaccount = "my_test_account"
fee = 100000
publicKey = "BANyQ50v/jWXz4dKpeXclE21aTgDJhmIgCCNH7sxAzuZqfSx6im19iqZjWRHlbrWh2dQC++aixYT+60a+kq9+Rg="

def request(method, params):
    unencoded_str = rpcuser + ":" + rpcpassword
    encoded_str = base64.b64encode(unencoded_str.encode())
    headers = {
        "content-type": "application/json",
        "Authorization": "Basic " + encoded_str.decode('utf-8')}
    payload = {
        "method": method,
        "params": params,
        "jsonrpc": "2.0",
        "id": 0,
    }
    response = requests.post(url, data=json.dumps(payload), headers=headers).json()
    return response

# retrieve an output to spend
toSpend = request("listunspentoutputs", {"password": walletpassword, "account": walletaccount})["result"]["outputs"][0]

# input wrapper spending output
input = {"outputId": toSpend["id"]}

# new output for spent funds (minus fee)
newOutput = {"value": toSpend["value"] - fee,
             "nonce": 0,
             "data": {"publicKey": publicKey}}

# the unsigned transaction
transaction = {
    "inputs": [input], 
    "outputs": [newOutput], 
    "timestamp": int(time.time()),
}
print(json.dumps(transaction, sort_keys=True, indent=4))

# have ckd sign the unsigned transaction for us
signed = request("signtransaction", {"transaction": transaction, "password": walletpassword})["result"]
print(json.dumps(signed, sort_keys=True, indent=4))

# broadcast the signed transaction on the network
success = request("sendrawtransaction", {"transaction": signed})["result"]
print(success)

Other output types

In the above section we created a pay-to-public-key output where a signature signed with the private key that belongs to the public key specified in the output is required to spent the output. There are currently two other output types supported by Cryptokernel: pay-to-anyone and pay-to-contract. The former allows you to create an output that can be spent by anyone without rules and the latter allows you to specify arbitrary rules for a valid spend.

Pay-to-anyone

To create a pay-to-anyone output, merely omit both the publicKey and contract data fields from the output you create. The output can then be spent by an empty input with no additional data required.

The newOutput variable from the previous section would become:

# new output for spent funds (minus fee)
newOutput = {"value": toSpend["value"] - fee, 
             "nonce": 0, 
             "data": {}}

Since output IDs are not allowed to collide, if there already exists a pay-to-anyone output of the value you desire you will be unable to create the new output without setting the nonce to a value that generates a unique output ID.

Pay-to-contract

Pay-to-contract outputs are covered in detail in the contracts guide.

Pay-to-schnorr-key

Cryptokernel supports MuSig Schnorr signatures that allow you to have O(1) verifiable n-of-n multisig outputs and aggregate n schnorr outputs into a single signature. The unit tests provide some examples of these transactions but they require the use of lower level C functions to generate the signatures so are still for advanced users. In the future we intend for Schnorr to replace ECDSA and pay-to-public-key entirely.