Example of starting a contract

Hint

Technical description of contracts implementation is given in module Docker Smart Contracts.

Description of program logic

This module reviews an example of how to create and run a simple smart contract. The contract performs summing up of 2x numbers transferred to the contract entry in call-transactions.

Program listing ‘’contract.py’’ on Python:

import json
import sys
import os

def find_param_value(params, name):
    for param in params:
        if param['key'] == name: return param['value']
    return None

if __name__ == '__main__':
    command = os.environ['COMMAND']
    tx = json.loads(os.environ['TX'])
    if command == 'CALL':
        a = find_param_value(tx['params'], 'a')
        b = find_param_value(tx['params'], 'b')
        if a is None or b is None: sys.exit(-1)
        print(json.dumps([{
            "key": '{0}+{1}'.format(a, b),
            "type": "integer",
            "value": a + b}], separators=(',', ':')))
    elif command == 'CREATE':
        sys.exit(0)
    else:
        sys.exit(-1)

Description of operation

  • The program expects to get the data structure in json format with the field “params”.
  • It reads the values of the “a” and “b” fields.
  • Returns the result as a value of fields “{a} + {b}” in json format.

Example of incoming parameters

"params":[
    {
        "key":"a",
        "type":"integer",
        "value":1
    },
    {
        "key":"b",
        "type":"integer",
        "value":2
    }
]

Installing a smart contract

  1. Download and install Docker for Developers for your operating system.
  2. Prepare a contract image. In the ‘’sum-contract-kv’’ folder, create the following files:
../../../_images/sum-contract-structure.png

Listing of run.sh file

#!/bin/sh

python contract.py

Dockerfile File Listing

FROM python:alpine3.8
ADD contract.py /
ADD run.sh /
RUN chmod +x run.sh
RUN apk add --no-cache --update iptables
CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"
  1. Install the image in Docker registry. Execute the following commands in the terminal:
docker run -d -p 5000:5000 --name registry registry:2
cd contracts/sum-contract-kv
docker build -t sum-contract-kv .
docker image tag sum-contract-kv localhost:5000/sum-contract-kv
docker start registry
docker push localhost:5000/sum-contract-kv
  1. Sign a transaction to create a smart contract. In this example, the transaction is signed with the key stored in the node keystore.

Hint

To create a key pair and the participant address, use the utility generators.jar. The procedure for creating a key pair is given in item 1 of the module “Connecting to the Network”. The rules for generating queries to the node are given in the module Node REST API.

Query Body

{
  "fee": 100000000,
  "image": "stateful-increment-contract:latest",
  "imageHash": "7d3b915c82930dd79591aab040657338f64e5d8b842abe2d73d5c8f828584b65",
  "contractName": "stateful-increment-contract",
  "sender": "3PudkbvjV1nPj1TkuuRahh4sGdgfr4YAUV2",
  "password": "",
  "params": [],
  "type": 103,
  "version": 1
 }

Sample query

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-API-Key: key word' -d '    { \
        "fee": 100000000, \
        "image": "stateful-increment-contract:latest", \
        "imageHash": "7d3b915c82930dd79591aab040657338f64e5d8b842abe2d73d5c8f828584b65", \
        "contractName": "stateful-increment-contract", \
        "sender": "3PudkbvjV1nPj1TkuuRahh4sGdgfr4YAUV2", \
        "password": "", \
        "params": [], \
        "type": 103, \
        "version": 1 \
    }' 'http://localhost:6862/transactions/sign'

Sample response

{
    "type": 103,
    "id": "ULcq9R7PvUB2yPMrmBdxoTi3bcRmQPT3JDLLLZVj4Ky",
    "sender": "3N3YTj1tNwn8XUJ8ptGKbPuEFNa9GFnhqew",
    "senderPublicKey": "3kW7vy6nPC59BXM67n5N56rhhAv38Dws5skqDsjMVT2M",
    "fee": 500000,
    "timestamp": 1550591678479,
    "proofs": [ "yecRFZm9iBLyDy93bDVaNo1PR5Qkkic7196GAgUt9TNH1cnQphq4yGQQ8Fxj4BYA4TaqYVw5qxtWzGMPQyVeKYv" ],
    "version": 1,
    "image": "stateful-increment-contract:latest",
    "imageHash": "7d3b915c82930dd79591aab040657338f64e5d8b842abe2d73d5c8f828584b65",
    "contractName": "stateful-increment-contract",
    "params": [],
    "height": 1619
}
  1. Send the signed transaction to the blockchain. The response from the sign method must be transferred to the input for the broadcast method.

Sample query

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-API-Key: key word' -d '{ \
{
    "type": 103, \
    "id": "ULcq9R7PvUB2yPMrmBdxoTi3bcRmQPT3JDLLLZVj4Ky", \
    "sender": "3N3YTj1tNwn8XUJ8ptGKbPuEFNa9GFnhqew", \
    "senderPublicKey": "3kW7vy6nPC59BXM67n5N56rhhAv38Dws5skqDsjMVT2M", \
    "fee": 500000, \
    "timestamp": 1550591678479, \
    "proofs": [ "yecRFZm9iBLyDy93bDVaNo1PR5Qkkic7196GAgUt9TNH1cnQphq4yGQQ8Fxj4BYA4TaqYVw5qxtWzGMPQyVeKYv" ], \
    "version": 1, \
    "image": "stateful-increment-contract:latest", \
    "imageHash": "7d3b915c82930dd79591aab040657338f64e5d8b842abe2d73d5c8f828584b65", \
    "contractName": "stateful-increment-contract", \
    "params": [], \
    "height": 1619 \
}
}' 'http://localhost:6862/transactions/broadcast'
  1. Use the transaction ID to check that the contract initiation transaction is placed in the blockchain.

http://localhost:6862/transactions/info/2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2

Sample response

{
    "type": 103,
    "id": "ULcq9R7PvUB2yPMrmBdxoTi3bcRmQPT3JDLLLZVj4Ky",
    "sender": "3N3YTj1tNwn8XUJ8ptGKbPuEFNa9GFnhqew",
    "senderPublicKey": "3kW7vy6nPC59BXM67n5N56rhhAv38Dws5skqDsjMVT2M",
    "fee": 500000,
    "timestamp": 1550591678479,
    "proofs": [ "yecRFZm9iBLyDy93bDVaNo1PR5Qkkic7196GAgUt9TNH1cnQphq4yGQQ8Fxj4BYA4TaqYVw5qxtWzGMPQyVeKYv" ],
    "version": 1,
    "image": "stateful-increment-contract:latest",
    "imageHash": "7d3b915c82930dd79591aab040657338f64e5d8b842abe2d73d5c8f828584b65",
    "contractName": "stateful-increment-contract",
    "params": [],
    "height": 1619
}

Smart Contract Execution

  1. Sign a call-transaction to call (execute) the smart contract.

In the ‘’contractID’’ field, specify the contract initialization transaction ID.

Query Body

{
    "contractId": "2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2",
    "fee": 10,
    "sender": "3PKyW5FSn4fmdrLcUnDMRHVyoDBxybRgP58",
    "type": 104,
    "version": 1,
    "params": [
        {
            "type": "integer",
            "key": "a",
            "value": 1
        },
        {
            "type": "integer",
            "key": "b",
            "value": 100

        }
    ]
}

Sample query

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-API-Key: key word' -d '{ \
    "contractId": "2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2", \
    "fee": 10, \
    "sender": "3PKyW5FSn4fmdrLcUnDMRHVyoDBxybRgP58", \
    "type": 104, \
    "version": 1, \
    "params": [ \
        { \
            "type": "integer", \
            "key": "a", \
            "value": 1 \
        }, \
        { \
            "type": "integer", \
            "key": "b", \
            "value": 100 \
\
        } \
    ] \
}' 'http://localhost:6862/transactions/sign'

Sample response

{
    "type": 104,
    "id": "9fBrL2n5TN473g1gNfoZqaAqAsAJCuHRHYxZpLexL3VP",
    "sender": "3PKyW5FSn4fmdrLcUnDMRHVyoDBxybRgP58",
    "senderPublicKey": "2YvzcVLrqLCqouVrFZynjfotEuPNV9GrdauNpgdWXLsq",
    "fee": 10,
    "timestamp": 1549365736923,
    "proofs": [
        "2q4cTBhDkEDkFxr7iYaHPAv1dzaKo5rDaTxPF5VHryyYTXxTPvN9Wb3YrsDYixKiUPXBnAyXzEcnKPFRCW9xVp4v"
    ],
    "version": 1,
    "contractId": "2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2",
    "params": [
        {
        "key": "a",
        "type": "integer",
        "value": 1
        },
        {
        "key": "b",
        "type": "integer",
        "value": 100
        }
    ]
}
  1. Send the signed transaction to the blockchain. The response from the sign method must be transferred to the input for the broadcast method.

Sample query

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-API-Key: key word' -d '{ \
"type": 104, \
"id": "9fBrL2n5TN473g1gNfoZqaAqAsAJCuHRHYxZpLexL3VP", \
"sender": "3PKyW5FSn4fmdrLcUnDMRHVyoDBxybRgP58", \
"senderPublicKey": "2YvzcVLrqLCqouVrFZynjfotEuPNV9GrdauNpgdWXLsq", \
"fee": 10, \
"timestamp": 1549365736923, \
"proofs": [ \
    "2q4cTBhDkEDkFxr7iYaHPAv1dzaKo5rDaTxPF5VHryyYTXxTPvN9Wb3YrsDYixKiUPXBnAyXzEcnKPFRCW9xVp4v" \
], \
"version": 1, \
"contractId": "2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2", \
"params": [ \
    { \
    "key": "a", \
    "type": "integer", \
    "value": 1 \
    }, \
    { \
    "key": "b", \
    "type": "integer", \
    "value": 100 \
    } \
] \
}' 'http://localhost:6862/transactions/broadcast'
  1. Get the result of smart contract execution by its ID.

http://localhost:6862/contracts/2sqPS2VAKmK77FoNakw1VtDTCbDSa7nqh5wTXvJeYGo2

Sample response

[
    {
        "key": "1+100",
        "type": "integer",
        "value": 101
    }
]