Blockchain experimental design: XuperChain SDK and contract function use

Experimental purpose

  1. Master the basic functions of XuperChian’s SDK
  2. Master the use of XuperChain’s contract functions

Experimental environment

XuperChain provides multi-language versions of the SDK (including JS, Golang, Java, Python) to facilitate users to use various functions of XuperChain in depth. Here we take Python as an example to show the basic API used by XuperChain SDK.

1. Python SDK installation

Install via pip

$ pip install xuper

2. Start Xchain service

$ cd output
$ bash control.sh start
/home/ubuntu/go/src/github.com/xuperchain/output/bin/xchain
/home/ubuntu/go/src/github.com/xuperchain/output/conf/env.yaml
2021/08/10 19:26:57 start create chain.bc_name:xuper
genesis_conf:./data/genesis/xuper.json env_conf:./conf/env.yaml
2021/08/10 19:26:57 create ledger succ.bc_name:xuper start xchain.cmd:nohup
/home/ubuntu/go/src/github.com/xuperchain/output/bin/xchain startup --conf
/home/ubuntu/go/src/github.com/xuperchain/output/conf/env.yaml
>/home/ubuntu/go/src/github.com/xuperchain/output/logs/nohup.out 2> & amp;1 & amp;
.start proc succ.
start finish.pid:17242
Done!

2.1 Check service status

Note that under the default configuration, the xchain service will listen to port 37101. You can use the following command to check the running status of the xchain service and ensure that the xchain service is running normally.

$ bin/xchain-cli status -H 127.0.0.1:37101
{<!-- -->
  "blockchains": [
    {<!-- -->
      "name": "xuper",
      "ledger": {<!-- -->
        "rootBlockid":
"d93c260ea5639a55e1fcad3df494495efad5c65d46e846b6db3a9194a4212886",
        "tipBlockid":
"e49133c3ffd655e1cf28401cb2cdadc33ce03141f0eb3f6611d3c5fa0dbda449",
        "trunkHeight": 23
      },
      "utxo": {<!-- -->
        "latestBlockid":
"e49133c3ffd655e1cf28401cb2cdadc33ce03141f0eb3f6611d3c5fa0dbda449",
        "lockKeyList": null,
        "utxoTotal": "100000000000023000000",
        "avgDelay": 0,
        "unconfirmed": 0,
        "maxBlockSize": 134217728,
        "reservedContracts": [],
        "forbiddenContract": {<!-- -->
          "moduleName": "",
          "contractName": "",
          "methodName": "",
          "args": {<!-- -->},
          "resource_limits": null
        },
        "newAccountResourceAmount": 1000,
        "irreversibleBlockHeight": 0,
        "irreversibleSlideWindow": 0,
        "gasPrice": {<!-- -->
          "cpu_rate": 1000,
          "mem_rate": 1000000,
          "disk_rate": 1,
          "xfee_rate": 1
} },
      "branchBlockid": [
        "e49133c3ffd655e1cf28401cb2cdadc33ce03141f0eb3f6611d3c5fa0dbda449"
] }
  ],
  "peers": null,
  "speeds": {<!-- -->}
}

2.1 Check HTTP gateway

The Python SDK connects to the xchain service through the HTTP gateway port (note that it is not the default RPC port 37101). You can use the following command to check the startup configuration of the xchain service.

$ cat conf/server.yaml
# rpcPort service listen port for xuperos
rpcPort: 37101
metricPort: 37200
# GWPort gateway service listen port for xchain
GWPort: 37301
# enableEndorser switch for endorser service
enableEndorser: true
#endorserHosts
endorserHosts:
  - "127.0.0.1:8848"
endorserModule: "default"
# enableEvent switch for event service
enableEvent: true
# eventAddrMaxConn the maximum number of subscription connections per IP of a
contract event, if 0 is unlimited
eventAddrMaxConn: 5
# enableTls switch for tls
enableTls: false
#tlsServerName
tlsServerName: localhost
# maxMsgSize set the max message size in bytes the server can receive.
# If this is not set, gRPC uses the default 4MB.
maxMsgSize: 134217728
# readBufSize lets you set the size of read buffer, this determines how much data
can be read at most for one read syscall.
# The default value for this buffer is 32KB.
# Zero will disable read buffer for a connection so data framer can access the
underlying conn directly.
readBufSize: 32768
# writeBufSize determines how much data can be batched before doing a write on
the wire.
# The corresponding memory allocation for this buffer will be twice the size to
keep syscalls low.
# The default value for this buffer is 32KB.
# Zero will disable the write buffer such that each write will be on underlying
connection.
# Note: A Send call may not directly translate to a write.
writeBufSize: 32768
# initWindowSize window size for stream
# The lower bound for window size is 64K and any value smaller than that will be
ignored
initWindowSize: 131072
# initConnWindowSize window size for a connection
# The lower bound for window size is 64K and any value smaller than that will be
ignored
initConnWindowSize: 65536

You can see that in line 5 of the server.yaml file, the GW port is 37301

3. Using Python SDK

Create a client instance and connect to the xuper service

import xuper
pysdk = xuper.XuperSDK("http://127.0.0.1:37301", "xuper")

You need to have your own account before sending transactions to the chain. You can restore the account from the private key file.

pysdk.readkeys("{xuperchain_path}/output/data/keys")

After restoring the account, you can create a contract account

new_account_name = pysdk.new_account()
print(new_account_name) # XC2023050120231001@xuper

Check account balance

pysdk.balance(new_account_name)

Carry out transfer operation

tx_id = pysdk.transfer(new_account_name, 2023, desc="start funds")

Query transaction and block information

# Waiting for uploading
# wait for a second...
# Query transactions
tx_info = pysdk.query_tx(tx_id)
# Query block pysdk.get_block(tx_info['blockid'])

Can be confirmed in CLI

$ bin/xchain-cli account balance XC2023050120231001@xuper -H 127.0.0.1:37101
2023

Deploy contract

Here we take the wasm contract as an example to show the process of using the contract function in the SDK. Move the compiled contract file counter.wasm to the output directory of xuperchain for subsequent use.
Deploy contract

contract_name = 'counter' + str(random.randint(100,1000000))
print("deploying...")
rsps = pysdk.deploy(new_account_name, contract_name,
open('{<!-- -->xuperchain_path}/output/data/counter.wasm','rb').read(),
{<!-- -->'creator':b'baidu'})
print(rsps)

pre-execution contract

rsps = pysdk.preexec(contract_name, "get", {<!-- -->"key":b"counter"})
print(rsps.decode())

Call the contract and take effect on the chain

for i in range(5):
    rsps = pysdk.invoke(contract_name, "increase", {<!-- -->"key":b"counter"})
    print(rsps)