This is based on source, published by ICON Foundation https://icon.foundation/?lang=en at
This specific exercise is based on and is tested locally on local emulated test environment.
Download tbears docker image build by ICON Foundation https://icon.foundation/, create a container, start the container, and finally attach stdin/stderr to the container.
$ sudo docker run -it --name local-tbears -p 9000:9000 iconloop/tbears:mainnet
[ ok ] Starting RabbitMQ Messaging Server: rabbitmq-server.
Made tbears_cli_config.json, keystore_test1 successfully
[2019-05-28 15:07:09 +0000] [516] [INFO] Starting gunicorn 19.9.0
[2019-05-28 15:07:09 +0000] [516] [INFO] Listening at: http://0.0.0.0:9000 (516)
[2019-05-28 15:07:09 +0000] [516] [INFO] Using worker: sanic.worker.GunicornWorker
[2019-05-28 15:07:09 +0000] [524] [INFO] Booting worker with pid: 524
[2019-05-28 15:07:10 +0000] [531] [INFO] Booting worker with pid: 531
[2019-05-28 15:07:10 +0000] [538] [INFO] Booting worker with pid: 538
[2019-05-28 15:07:10 +0000] [545] [INFO] Booting worker with pid: 545
[2019-05-28 15:07:10 +0000] [552] [INFO] Booting worker with pid: 552
[2019-05-28 15:07:10 +0000] [559] [INFO] Booting worker with pid: 559
[2019-05-28 15:07:10 +0000] [566] [INFO] Booting worker with pid: 566
[2019-05-28 15:07:10 +0000] [573] [INFO] Booting worker with pid: 573
[2019-05-28 15:07:10 +0000] [580] [INFO] Booting worker with pid: 580
Started tbears service successfully
root@23fe8202ab1d:/work#
You can now exit and stop the container as:
root@23fe8202ab1d:/work# exit
exit
$
Let's see the container list. You see below two containers; local-tbears and tbears-container. This local-tbears is the one that we deployed for this exercise.
$ sudo docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23fe8202ab1d iconloop/tbears:mainnet "entry.sh" 5 minutes ago Exited (127) About a minute ago local-tbears
327360362eba iconloop/tbears:mainnet "entry.sh" 6 hours ago Exited (0) 18 minutes ago tbears-container
Now let's start and attach to the container local-tbears (or if the container local-tbears has already been running, then just attach to it).
$ sudo docker container start -a local-tbears
[ ok ] Starting RabbitMQ Messaging Server: rabbitmq-server.
There were configuration files already.
[2019-05-28 15:19:05 +0000] [536] [INFO] Starting gunicorn 19.9.0
[2019-05-28 15:19:05 +0000] [536] [INFO] Listening at: http://0.0.0.0:9000 (536)
[2019-05-28 15:19:05 +0000] [536] [INFO] Using worker: sanic.worker.GunicornWorker
[2019-05-28 15:19:05 +0000] [544] [INFO] Booting worker with pid: 544
[2019-05-28 15:19:05 +0000] [551] [INFO] Booting worker with pid: 551
[2019-05-28 15:19:05 +0000] [558] [INFO] Booting worker with pid: 558
[2019-05-28 15:19:05 +0000] [565] [INFO] Booting worker with pid: 565
[2019-05-28 15:19:05 +0000] [572] [INFO] Booting worker with pid: 572
[2019-05-28 15:19:05 +0000] [579] [INFO] Booting worker with pid: 579
[2019-05-28 15:19:05 +0000] [586] [INFO] Booting worker with pid: 586
[2019-05-28 15:19:05 +0000] [593] [INFO] Booting worker with pid: 593
[2019-05-28 15:19:05 +0000] [600] [INFO] Booting worker with pid: 600
Started tbears service successfully
root@23fe8202ab1d:/work#
$ sudo docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23fe8202ab1d iconloop/tbears:mainnet "entry.sh" 13 minutes ago Up About a minute 0.0.0.0:9000->9000/tcp local-tbears
327360362eba iconloop/tbears:mainnet "entry.sh" 6 hours ago Exited (0) 26 minutes ago tbears-container
$ sudo docker container attach local-tbears
root@23fe8202ab1d:/work#
keystore_test1There comes a test keystore file, keystore_test1, as part of standard tbears docker image installation. Please remember that never to use this keystore file to sign your transaction to any network other than T-Bears local test environment. The password to protect this keystore file public.
root@23fe8202ab1d:/work# ls -lai
total 236
7216762 drwxr-xr-x 1 root root 4096 May 28 15:26 .
7216892 drwxr-xr-x 1 root root 4096 May 28 15:06 ..
7216763 drwxr-xr-x 3 root root 4096 May 22 09:16 .score
7216786 drwxr-xr-x 1 root root 4096 May 22 09:16 .statedb
7216799 drwxr-xr-x 1 root root 4096 May 22 09:16 exc
7216976 -rw-r--r-- 1 root root 675 May 28 15:07 keystore_test1
7216802 -rw-r--r-- 1 root root 194828 May 28 15:26 tbears.log
7216975 -rw-r--r-- 1 root root 386 May 28 15:07 tbears_cli_config.json
7209490 -rw-r--r-- 1 root root 1283 Apr 2 13:24 tbears_server_config.json
root@23fe8202ab1d:/work# more keystore_test1
{
"address": "hxe7af5fcfd8dfc67530a01a0e403882687528dfcb",
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": {
"iv": "dc0762c56ca56cd06038df5051c9e23e"
},
"ciphertext": "7cc40efac0b14eaf56f951c9c9620f9f34bac548175e85052aa9f753423dc984",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 16384,
"r": 1,
"p": 8,
"salt": "380c00457be5fd1c244f5745c322b21f"
},
"mac": "157dda6fb7092df62ff93411bed54e5a64dbf06c1aae3b375d356061a9c3dfd1"
},
"id": "e2ca66c6-b8de-4413-82cb-52c2a2200b8d",
"version": 3,
"coinType": "icx"
}
This is how you can check balance by using tbears balance command for test keystore file keystore_test1 account with address = hxe7af5fcfd8dfc67530a01a0e403882687528dfcb
root@23fe8202ab1d:/work# tbears balance hxe7af5fcfd8dfc67530a01a0e403882687528dfcb
balance in hex: 0x2961ffe7671f19843b0b000
balance in decimal: 800459979953716600000000000
Now it is the time to create HelloWorld smart contract (HelloWorld SCORE) and deploy it on ICON Blockchain on local emulated environment.
Start by initializing a project with tbears init command.
root@23fe8202ab1d:/work# tbears init hello_world HelloWorld
Initialized hello_world successfully
root@23fe8202ab1d:/work# ls -lai
total 240
7216762 drwxr-xr-x 1 root root 4096 May 28 15:45 .
7216892 drwxr-xr-x 1 root root 4096 May 28 15:06 ..
7216763 drwxr-xr-x 3 root root 4096 May 22 09:16 .score
7216786 drwxr-xr-x 1 root root 4096 May 22 09:16 .statedb
7216799 drwxr-xr-x 1 root root 4096 May 22 09:16 exc
7216968 drwxr-xr-x 3 root root 4096 May 28 15:45 hello_world
7216976 -rw-r--r-- 1 root root 675 May 28 15:07 keystore_test1
7216802 -rw-r--r-- 1 root root 195832 May 28 15:38 tbears.log
7216975 -rw-r--r-- 1 root root 386 May 28 15:07 tbears_cli_config.json
7209490 -rw-r--r-- 1 root root 1283 Apr 2 13:24 tbears_server_config.json
root@23fe8202ab1d:/work# ls -lai hello_world/
total 24
7216968 drwxr-xr-x 3 root root 4096 May 28 15:45 .
7216762 drwxr-xr-x 1 root root 4096 May 28 15:45 ..
7217017 -rw-r--r-- 1 root root 0 May 28 15:45 __init__.py
7217015 -rw-r--r-- 1 root root 420 May 28 15:45 hello_world.py
7217016 -rw-r--r-- 1 root root 92 May 28 15:45 package.json
7217018 drwxr-xr-x 2 root root 4096 May 28 15:45 tests
Please note that hello_world.py has the SCORE implementation template which is fully functional.
root@23fe8202ab1d:/work# more hello_world/hello_world.py
from iconservice import *
TAG = 'HelloWorld'
class HelloWorld(IconScoreBase):
def __init__(self, db: IconScoreDatabase) -> None:
super().__init__(db)
def on_install(self) -> None:
super().on_install()
def on_update(self) -> None:
super().on_update()
@external(readonly=True)
def hello(self) -> str:
Logger.debug(f'Hello, world!', TAG)
return "Hello"
Now, let's deploy the smart contract (SCORE) without modification and get the contract address. Please note that for every transaction, you must check the execution result using txhash. Transaction result must contain the SCORE address if the deployment was successful.
root@fb8134dddbe9:/work# tbears deploy hello_world
Send deploy request successfully.
If you want to check SCORE deployed successfully, execute txresult command
transaction hash: 0xb2ceb3e2ec3e92a4f663169c086d632d87360f07b9af83267beb7277c80f5663
root@fb8134dddbe9:/work# tbears txresult 0xb2ceb3e2ec3e92a4f663169c086d632d87360f07b9af83267beb7277c80f5663
Transaction result: {
"jsonrpc": "2.0",
"result": {
"txHash": "0xb2ceb3e2ec3e92a4f663169c086d632d87360f07b9af83267beb7277c80f5663",
"blockHeight": "0x6",
"blockHash": "0x81f1361c973ff66ea515d26d7112420b5d8fa99c8facc20f8bc97e405156b830",
"txIndex": "0x0",
"to": "cx0000000000000000000000000000000000000000",
"scoreAddress": "cx8a71f8f0ad1e605e37d7d41c9ef83600808d0d11",
"stepUsed": "0x3cdba380",
"stepPrice": "0x2540be400",
"cumulativeStepUsed": "0x3cdba380",
"eventLogs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1"
},
"id": 1
}
The SCORE has now been successfully deployed on local ICON emulated environment. We can, of course, now invoke hello method from CLI and see the result.
Note that the file call.json contains the request message. Where;
to is the SCORE address,from is the message sender's public address.Please also note that here you must provide the actual SCORE address. Meaning, the one that you got after deployment of hello_world SCORE.
root@fb8134dddbe9:/work# cat call.json
{
"jsonrpc": "2.0",
"method": "icx_call",
"id": 1,
"params": {
"from": "hxe7af5fcfd8dfc67530a01a0e403882687528dfcb",
"to": "cx8a71f8f0ad1e605e37d7d41c9ef83600808d0d11",
"dataType": "call",
"data": {
"method": "hello"
}
}
}
root@fb8134dddbe9:/work# tbears call call.json
response : {
"jsonrpc": "2.0",
"result": "Hello",
"id": 1
}
Let's now modify HelloWorld SCORE. We will give it a name. It will greet you in a nicer way. We will add one more method. We will also modify hello method.
name as read-only funtion. It will return the SCORE name, which is HelloWorldhello method.
msg is a built-in property that holds information of the message sender, and the *amount of ICX tokens the sender attempts to transfer. They can be referenced by msg.sender and msg.value. @external(readonly=True)
def name(self) -> str:
return "HelloWorld"
@external(readonly=True)
def hello(self) -> str:
return f'Hello, {self.msg.sender}. My happy name is {self.name()}'
root@fb8134dddbe9:/work# more hello_world/hello_world.py
from iconservice import *
TAG = 'HelloWorld'
class HelloWorld(IconScoreBase):
def __init__(self, db: IconScoreDatabase) -> None:
super().__init__(db)
def on_install(self) -> None:
super().on_install()
def on_update(self) -> None:
super().on_update()
@external(readonly=True)
def name(self) -> str:
return "HelloWorld"
@external(readonly=True)
def hello(self) -> str:
return f'Hello, {self.msg.sender}. My happy name is {self.name()}'
We will now deploy the SCORE, once again, to reflect the above changes. We will use deploy command with -m update and -o [score_address] options to update the SCORE. Please also know that this updating is a unique feature of ICON Blockchain. The SCORE address is not at all changed after update has been deployed.
root@fb8134dddbe9:/work# tbears deploy -m update -o cx8a71f8f0ad1e605e37d7d41c9ef83600808d0d11 hello_world
Send deploy request successfully.
If you want to check SCORE deployed successfully, execute txresult command
transaction hash: 0x6008f1fbbf128c93c9922f0317e6fb53f50b1cb862355d2b0c195d583e7834f6
root@fb8134dddbe9:/work# tbears txresult 0x6008f1fbbf128c93c9922f0317e6fb53f50b1cb862355d2b0c195d583e7834f6
Transaction result: {
"jsonrpc": "2.0",
"result": {
"txHash": "0x6008f1fbbf128c93c9922f0317e6fb53f50b1cb862355d2b0c195d583e7834f6",
"blockHeight": "0xa",
"blockHash": "0x2352fa37e7e6d7b3d8c41d8d2754eae881544feb1bb0901ab01e7bcba4d062bb",
"txIndex": "0x0",
"to": "cx8a71f8f0ad1e605e37d7d41c9ef83600808d0d11",
"scoreAddress": "cx8a71f8f0ad1e605e37d7d41c9ef83600808d0d11",
"stepUsed": "0x60a47a80",
"stepPrice": "0x2540be400",
"cumulativeStepUsed": "0x60a47a80",
"eventLogs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1"
},
"id": 1
}
Now, let's invoke and call the hello method with the same request message, and see the changes.
root@fb8134dddbe9:/work# tbears call call.json
response : {
"jsonrpc": "2.0",
"result": "Hello, hxe7af5fcfd8dfc67530a01a0e403882687528dfcb. My happy name is HelloWorld",
"id": 1
}