FISCO BCOS Overview¶
FISCO BCOS is an open-sourced, cross-industry, collaborative, and secure blockchain platform. Two major camps of blockchain technology - public and consortium chains, to better serve the general public, open consortium chain is the perfect choice for enterprises to unlock the potential of collaborative businesses model. FISCO BCOS is born to support open consortium chain applications, by supporting multiple chains, and cross-chain communication.
The community - Financial Blockchain Shenzhen Consortium (FISCO) is established on May 31, 2016. It has attracted more than 100 members including financial institutions and financial information service companies so far. The first members include the following organizations: Beyondsoft, Huawei, Shenzheng, Shenzhou Digital, Forms Syntron, Tencent, WeBank, Yuexiu Jinke.
FISCO BCOS is developed based on the existing BCOS open-sourced platform. Focusing on collaborative businesses model cross industry, considering from multiple dimensions such as business suitability, performance, security, normality, technical feasibility, operation & governance, and cost, to finally provide a blockchain solution.
Based on FISCO BCOS’s blockchain platform, different blockchain scenarios can be quickly built, with following benefits:
- For banking institutions, it can reduce the settlement cost, improve the efficiency of the operation of the middle and back offices, and improve the automation of the process.
- For non-banking financial institutions, it can enhance the authority of equity registration, information deposit, reduce the risk of counterparty, solve data tracking and information anti-counterfeiting problems, and reduce the operating costs of auditing.
- For financial regulators, it provides consistent and easy-to-audit data. Through data analysis of inter-agency blockchains, financial services can be regulated faster and more accurately than traditional audit process, and anti-money laundering can be strengthened.
- Others, in cross-border financial scenarios, it helps to achieve ledger sharing among the institutions, reduce the cost of inter-bank reconciliation and settlement, and dispute friction costs, thereby improving the processing speed and efficiency of cross-border businesses.
So, what is FISCO BCOS? It is a platform/community with software developers building blockchain frameworks and solutions.
The open source license for FISCO BCOS is GPL3.0.
Contribute on Github.
Read the Whitepaper.
Advance Messages Onchain Protocol¶
Author: fisco-dev
Introduction¶
AMOP (Advance Messages Onchain Protocol) aims to provide a safe and efficient message channel. In consortium chain, all nodes, no matter consensus node or observation node, can use AMOP as the message channel with the following advantages:
- Real-time: AMOP messages do not rely on transactions and consensus. Messages are transmitted nearly real-time with only a few milliseconds delay between nodes.
- Reliable: When the message is transmitted by AMOP, it will leverage any feasible routes in the blockchain network.The message is guaranteed to be reachable as long as at least one route is available between sender and receiver node.
- Efficient: AMOP protocol is concise and clean. It takes very minimized CPU and network bandwidth.
- Secure: Supports SSL encryption on the network and the encryption algorithm is configurable.
- Easy to use: AMOP is embedded in the SDK.
Network Architecture¶
Take the classic IDC (Internet Data Center) bank architecture as an example:
- SF (Server Farm) area: Applications within the organization’s intranet can leverage the SDK to send AMOP messages to the proxy. If there is no DMZ, applications will link to blockchain nodes directly.
- DMZ (Demilitarized Zone) area: Physical or logical isolated network. This area is optional but recommended for better security.
- Blockchain P2P network: The logical area which contains blockchain nodes from different organizations. This is usually deployed within the DMZ zone but can also be placed in the SF area.
- Proxy Server: Responsible for forwarding messages from internal applications to the blockchain P2P network. It is recommended to place the proxy inside DMZ.
Configuration¶
Below is a sample code for sending AMOP messages (Spring Bean):
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- Thread pool configuration, config as needs -->
<bean id="pool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="50" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="500" />
<property name="keepAliveSeconds" value="60" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor.AbortPolicy" />
</property>
</bean>
<!-- Blockchain nodes configuration -->
<bean id="channelService" class="cn.webank.channel.client.Service">
<property name="orgID" value="WB" /> <!-- Configure the organization's name -->
<property name="allChannelConnections">
<map>
<entry key="WB"> <!-- Setup SDK to link to the blockchain proxy in DMZ. If no DMZ, link to blockchain node directly.-->
<bean class="cn.webank.channel.handler.ChannelConnections">
<property name="connectionsStr">
<list>
<value>NodeA@127.0.0.1:30333</value><!-- Format: Node name @ IP address: Port Node name can be any -->
</list>
</property>
</bean>
</entry>
</map>
</property>
</bean>
</bean>
If DMZ is used, the below is require to configured for the proxy server:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- Blockchain nodes configuration -->
<bean id="proxyServer" class="cn.webank.channel.proxy.Server">
<property name="remoteConnections">
<bean class="cn.webank.channel.handler.ChannelConnections">
<property name="connectionsStr">
<list>
<value>NodeA@127.0.0.1:5051</value><!-- Format: Node name @ IP address: Port Node name can be any -->
</list>
</property>
</bean>
</property>
<property name="localConnections">
<bean class="cn.webank.channel.handler.ChannelConnections">
</bean>
</property>
<!-- Proxy listening port config for SDK connection -->
<property name="bindPort" value="30333"/>
</bean>
</beans>
How to use SDK¶
The sending and receiving is based on publish-subscribe pattern. The server creates the topic and subscribes to it. Clients connect to the topic to send message to the server.
Multiple topics are supported in a blockchain. There is no limitation for the number of servers and clients. If multiple servers are subscribing to the same topic, only the first available server will receive the message.
Server-side example:
package cn.webank.channel.test;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.webank.channel.client.Service;
public class Channel2Server {
static Logger logger = LoggerFactory.getLogger(Channel2Server.class);
public static void main(String[] args) throws Exception {
if(args.length < 1) {
System.out.println("Parameters: Receive topic");
return;
}
String topic = args[0];
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Service service = context.getBean(Service.class);
//config topic, support multiple topic
List<String> topics = new ArrayList<String>();
topics.add(topic);
service.setTopics(topics);
//handle PushCallback class, see Callback code
PushCallback cb = new PushCallback();
service.setPushCallback(cb);
//run server
service.run();
}
}
Server-side PushCallback example:
package cn.webank.channel.test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.webank.channel.client.ChannelPushCallback;
import cn.webank.channel.dto.ChannelPush;
import cn.webank.channel.dto.ChannelResponse;
class PushCallback extends ChannelPushCallback {
static Logger logger = LoggerFactory.getLogger(PushCallback2.class);
//onPush function, Called when the AMOP message is received
@Override
public void onPush(ChannelPush push) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
logger.debug("Received PUSH message:" + push.getContent());
System.out.println(df.format(LocalDateTime.now()) + "server:Received PUSH message:" + push.getContent());
//Response
ChannelResponse response = new ChannelResponse();
response.setContent("receive request seq:" + String.valueOf(push.getMessageID()));
response.setErrorCode(0);
push.sendResponse(response);
}
}
Client-side example:
package cn.webank.channel.test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.webank.channel.client.Service;
import cn.webank.channel.dto.ChannelRequest;
import cn.webank.channel.dto.ChannelResponse;
public class Channel2Client {
static Logger logger = LoggerFactory.getLogger(Channel2Client.class);
public static void main(String[] args) throws Exception {
if(args.length < 1) {
System.out.println("Parameters: target topic");
return;
}
String topic = args[0];
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Service service = context.getBean(Service.class);
service.run();
Thread.sleep(2000); //It takes a little time to set up the connection, and if the message is sent immediately, it will fail
ChannelRequest request = new ChannelRequest();
request.setToTopic(topic); //Set message's topic
request.setMessageID(service.newSeq()); //Message sequence number that uniquely identifies a message, use newSeq() random generate
request.setTimeout(5000); //Timeout of message
request.setContent("request seq:" + request.getMessageID()); //Message content
ChannelResponse response = service.sendChannelMessage2(request); //Send message
System.out.println(df.format(LocalDateTime.now()) + "Received response seq:" + String.valueOf(response.getMessageID()) + ", Error code:" + response.getErrorCode() + ", message content:" + response.getContent());
}
}
Running the test app locally¶
After creating the above configurations, you can start the AMOP server and client with the below command lines:
Start AMOP server:
java -cp 'conf/:apps/*:lib/*' cn.webank.channel.test.Channel2Server [topic name]
Start AMOP client
java -cp 'conf/:apps/*:lib/*' cn.webank.channel.test.Channel2Client [topic name] [message content] [number of messages]
Error Code¶
- 99: Message failed to deliver as there is no available route to the destination server. Check the node status with the sequence number(seq) generated while sending message as well as verify the route status.
- 102: Connection Timeout. The server may be overloaded or not reachable.
Contract Name Service¶
Overview¶
1.Steps to call a smart contract¶
Implement a smart contract includes steps: coding, compiling and deploying. Take HelloWorld.sol as an example:
// HelloWorld.sol path: FISCO-BCOS/tool/HelloWorld.sol
pragma solidity ^0.4.2;
contract HelloWorld{
string name;
function HelloWorld(){
name="Hi,Welcome!";
}
function get()constant returns(string){
return name;
}
function set(string n){
name=n;
}
}
After compiling the contract, a description of the contract interface - ABI - is provided as follows:
[
{
"constant": false,
"inputs": [
{
"name": "n",
"type": "string"
}
],
"name": "set",
"outputs": [
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
],
"name": "get",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
}
]
Deploy the contract to the blockchain to generate an address, Such as: 0x269ab4bc23b07efeb3c3fd52eecfc4cbe6a50859. Finally, use the ABI and address to call the smart contract. The key input parameters are ABI and address even there are different SDK tools.
2. Brief to CNS¶
ABI and contract address are mandatory when we trigger the smart contract. Below are some disadvantages of using the ABI and contract address directly.
- The ABI is a lengthy JSON string which is not user-friendly.
- Contract address is a magic number which is difficult to remember and can easily type wrong.
- The contract will be unreachable if the address had been forgotten.
- The contract address is changed after deployment.
- It is difficult to manage versioning and contract gated-upgrade.
With the CNS in place, we see the following advantages as a caller:
- No longer need to maintain the ABI and contract address.
- Only needs to know the contract name, version, function name and parameters
- Contract upgrade is transparent to the caller
- Supports gated-upgrade for contracts
How it works¶
1. Overall framework¶
The client calls the contract service by RPC, first it will visit contract naming service to get underlying business contract details (ABI and address), then construct a call to business smart contract by using it’s ABI and address, and finally return the results to the client.
2. Key components¶
a. Contract Manager¶
Contract manager contains mapping between the name and contract information. CNS Manager (cns_manager.js) is a tool that allows us to add, update, list and reset the mappings. Any changes made with the tool will be synchronized to the systems automatically.
Mapping in the contract manager:
Key: contract name, contract version number Value: ABI, address.
Sample implementation code: systemcontractv2/ContractAbiMgr.sol
Abstract Contract: tool/ContractBase.sol
Provide multi-version management by inheriting from ContractBase.sol, and initializing ContractAbiMgr with version number.
ContractAbiMgr is managed by system contract, system contract should be deployed before applying CNS.
b. CNS Manager Tool¶
Provide add, update, list and reset naming mapping information by calling contract manager.
- Tool: tool/cns_manager.js
babel-node cns_manager.js
cns_manager.js Usage:
babel-node cns_manager.js get contractName [contractVersion]
babel-node cns_manager.js add contractName
babel-node cns_manager.js update contractName
babel-node cns_manager.js list [simple]
babel-node cns_manager.js historylist contractName [contractVersion] [simple]
babel-node cns_manager.js reset contractName [contractVersion] index
List of utility methods:
- Command : add
- Parameter : contractName
- Function : add contract name to contract management
- Note : Duplicate contract name raise warning. This can be resolve in following two ways: 1. change the contract version and specify the version number during calling by CNS. or 2. overwrite mapping in contract manager by calling ‘update’ command.
//first time add Test, success
babel-node cns_manager.js add Test
cns add operation => cns_name = Test
cns_name =>Test
contract =>Test
version =>
address =>0x233c777fccb9897ad5537d810068f9c6a4344e4a
abi =>[{"constant":false,"inputs":[{"name":"num","type":"uint256"}],"name":"trans","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"Ok","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
//second time add, failed
babel-node cns_manager.js add Test
cns_manager.js ........................Begin........................
[WARNING] cns add operation failed , ====> contract => Test version => already exist. you can update it or change its version.
- Command : get
- Parameter : 1. contractName 2. contractVersion [optional]
- Description : Get contract information by name and version
babel-node cns_manager.js get HelloWorld
cns_manager.js ........................Begin........................
====> contract => HelloWorld ,version =>
contract = HelloWorld
version =
address = 0x269ab4bc23b07efeb3c3fd52eecfc4cbe6a50859
timestamp = 1516866720115 => 2018/1/25 15:52:0:115
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
- Command : update
- Parameter : contractName
- Description : Update stored contract information
- Note : 1, Failure in case the corresponding contract does not exist. To resolve, add the missing contract first; 2, The overwritten information can be queried by ‘historylist’ command and reset by ‘reset’ command.
babel-node cns_manager.js update Test
cns_manager.js ........................Begin........................
====> Are you sure you want to update the cns of the contract ?(Y/N)
Y
cns update operation => cns_name = Test
cns_name =>Test
contract =>Test
version =>
address =>0x233c777fccb9897ad5537d810068f9c6a4344e4a
abi =>[{"constant":false,"inputs":[{"name":"num","type":"uint256"}],"name":"trans","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"Ok","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Send transaction successfully: 0x1d3caff1fba49f5ad8af3d195999454d01c64d236d9ac3ba91350dd543b10c13
- Command : list
- Parameter : simple[optional]
- Description : List all the existing mappings in the contract manager. Display the contract name and version in case option ‘simple’ provided, else display all the details.
babel-node cns_manager.js list simple
cns_manager.js ........................Begin........................
cns total count => 11
1. contract = ContractAbiMgr ,version =
2. contract = SystemProxy ,version =
3. contract = TransactionFilterChain ,version =
4. contract = AuthorityFilter ,version =
5. contract = Group ,version =
6. contract = CAAction ,version =
7. contract = ConfigAction ,version =
8. contract = NodeAction ,version =
9. contract = HelloWorld ,version =
10. contract = Ok ,version =
11. contract = Test ,version =
- Command : historylist
- Parameter : 1. contract name | 2, contract version [optional]
- Description : Display all update history for provided contract
babel-node cns_manager.js historylist HelloWorld
cns_manager.js ........................Begin........................
cns history total count => 3
====> cns history list index = 0 <====
contract = HelloWorld
version =
address = 0x1d2047204130de907799adaea85c511c7ce85b6d
timestamp = 1516865606159 => 2018/1/25 15:33:26:159
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
====> cns history list index = 1 <====
contract = HelloWorld
version =
address = 0x9c3fb4dd0a3fc5e1ea86ed3d3271b173a7084f24
timestamp = 1516866516542 => 2018/1/25 15:48:36:542
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
====> cns history list index = 2 <====
contract = HelloWorld
version =
address = 0x1d2047204130de907799adaea85c511c7ce85b6d
timestamp = 1516866595160 => 2018/1/25 15:49:55:160
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
- Command : reset
- Parameter : 1. contract name 2. contract version [optional] 3. index
- Description : Resets the information in contract manager from its history at the specified index.
c. RPC interface¶
The base class of the RPC interface is modified to support CNS
RPC interface is modified such that it is backward compatible to Ethereum call RPC format details: https://github.com/ethereum/wiki/wiki/JSON-RPC
- eth_call
request:
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"data": {
"contract": "",
"version": "",
"func": "",
"params": [
]
}
},
"latest"
],
"id": 1
}
response:
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"result": [], //return result, json format
"ret_code": 0,
"ret_msg": "success!"
}
}
- eth_sendRawTransaction The RPC request and response format are the same except the ‘data’ field which is encoded as RLP HEX string.
"data": {
"contract": "",
"version": "",
"func": "",
"params": [
]
}
d. JavaScript RPC call¶
Path: web3lib/web3sync.jsInterface:
callByNameService
sendRawTransactionByNameService
Examples¶
// Test contract
// Path tool/HelloWorld.sol
pragma solidity ^0.4.4;
contract HelloWorld{
string name;
function HelloWorld(){
name="Hi,Welcome!";
}
function get()constant public returns(string){
return name;
}
function set(string n) public{
name=n;
}
}
- Deployment:babel-node deploy.js HelloWorld
When contract gets deployed successfully, the cns_manager add function is called by default, and the file name would be same as the contract name. In case of failure, action as below:
- Call ‘cns_manager add’ again if a specific name is needed.
- No action needed for a test contract.
- Call ‘cns_manager update’ for bug fix or upgrade.
- Modify the contract’s version if previous contract is still in use (refer to multi-version deployment).
//examples of success
babel-node deploy.js Test0
deploy.js ........................Start........................
Soc File :Test0
Test0Compiled successfully!
Test0Contract address 0xfc7055a9dc68ff79a58ce4f504d8c780505b2267
Test0Deployed successful !
cns add operation => cns_name = Test0
cns_name =>Test0
contract =>Test0
version =>
address =>0xfc7055a9dc68ff79a58ce4f504d8c780505b2267
abi =>[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"HelloWorld","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Send transaction successfully: 0x84d1e6b16c58e3571f79e80588472ab8d12779234e75ceed4ac592ad1d653086
//Example of failure, the contract already has corresponding information
babel-node deploy.js HelloWorld
deploy.js ........................Start........................
Soc File :HelloWorld
HelloWorld Compiled successfully!
HelloWorld Contract address 0xc3869f3d9a5fc728de82cc9c807e85b77259aa3a
HelloWorld Deployed successful !
[WARNING] cns add operation failed , ====> contract => HelloWorld version => is already exist. you can update it or change its version.
Multi-version Deployment In case multi-version Deployment using ‘cns_manager add’ fails due to duplicate version, modify the contract version by providing unique version number in the constructor of ContractBase.sol.
pragma solidity ^0.4.4;
contract HelloWorld is ContractBase("v-1.0"){
string name;
function HelloWorld(){
name="Hi,Welcome!";
}
function get()constant public returns(string){
return name;
}
function set(string n) public{
name=n;
}
}
re-deploy
babel-node deploy.js HelloWorld
deploy.js ........................Start........................
Soc File :HelloWorld
HelloWorldCompiled successfully!
HelloWorldContract address 0x027d156c260110023e5bd918cc243ac12be45b17
HelloWorldDeployed successful !
cns add operation => cns_name = HelloWorld/v-1.0
cns_name =>HelloWorld/v-1.0
contract =>HelloWorld
version =>v-1.0
address =>0x027d156c260110023e5bd918cc243ac12be45b17
abi =>[{"constant":true,"inputs":[],"name":"getVersion","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"version_para","type":"string"}],"name":"setVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
Send transaction successfully: 0x9a409003f5a17220809dd8e1324a36a425acaf194efd3ef1f772bbf7b49ee67c
The latest contract version is v-1.0
- RPC calls
1. get - HelloWorld contract default version
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"HelloWorld","version":"","func":"get","params":[]}},"latest"],"id":1}' "http://127.0.0.1:8746"
{"id":1,"jsonrpc":"2.0","result":"[\"call defaut version\"]\n"}
2. get - HelloWorld contract version v-1.0
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"HelloWorld","version":"v-1.0","func":"get","params":[]}},"latest"],"id":1}' "http://127.0.0.1:8746"
{"id":1,"jsonrpc":"2.0","result":"[\"call v-1.0 version\"]\n"}
- Upgrade contract Contract can be upgraded using ‘update’ command. If cns_manager has HelloWorld added already with old address, in order to be able to redeploy and upgrade HelloWorld, it requires to use ‘update’ command to avoid failure while adding.
babel-node cns_manager.js update HelloWorld
cns_manager.js ........................Begin........................
====> Are you sure update the cns of the contract ?(Y/N)
Y
cns update operation => cns_name = HelloWorld
cns_name =>HelloWorld
contract =>HelloWorld
version =>
address =>0x93d62e961a6801d3f614a5add207cdf45b0ff654
abi =>[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
Send transaction successfully: 0xc8ee384185a1aaa3817474d6db6394ff6871a7bc56a15e564e7b1f57c8bfda1a
Call get interface again:
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"HelloWorld","version":"","func":"get","params":[]}},"latest"],"id":1}' "http://127.0.0.1:8746"
{"id":1,"jsonrpc":"2.0","result":"[\"Hi,Welcome!\"]\n"}
Return 'Hi,Welcome!'.
That means the current contract is the newly deployed contract.
- Reset contractUse ‘reset’ to recover the original contract after the update. First, list history of updated contract.
babel-node cns_manager.js historylist HelloWorld
cns_manager.js ........................Begin........................
cns history total count => 4
====> cns history list index = 0 <====
contract = HelloWorld
version =
address = 0x1d2047204130de907799adaea85c511c7ce85b6d
timestamp = 1516865606159 => 2018/1/25 15:33:26:159
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
====> cns history list index = 1 <====
contract = HelloWorld
version =
address = 0x9c3fb4dd0a3fc5e1ea86ed3d3271b173a7084f24
timestamp = 1516866516542 => 2018/1/25 15:48:36:542
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
====> cns history list index = 2 <====
contract = HelloWorld
version =
address = 0x1d2047204130de907799adaea85c511c7ce85b6d
timestamp = 1516866595160 => 2018/1/25 15:49:55:160
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
====> cns history list index = 3 <====
contract = HelloWorld
version =
address = 0x269ab4bc23b07efeb3c3fd52eecfc4cbe6a50859
timestamp = 1516866720115 => 2018/1/25 15:52:0:115
abi = [{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
Then find out which history item need to be retrieved.
babel-node cns_manager.js reset HelloWorld 3
cns_manager.js ........................Begin........................
====> Are you sure update the cns of the contract ?(Y/N)
Y
cns update operation => cns_name = HelloWorld
cns_name =>HelloWorld
contract =>HelloWorld
version =>
address =>0x269ab4bc23b07efeb3c3fd52eecfc4cbe6a50859
abi =>[{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
Send transaction successfully: 0x4809a6105916a483ca70c4efe8e306bc01ca5d937515320d09e94a83f4a91b76
Then execute 'get' command with contract name as HelloWorld one more time:
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"HelloWorld","version":"","func":"get","params":[]}},"latest"],"id":1}' "http://127.0.0.1:8746"
{"id":1,"jsonrpc":"2.0","result":"[\"call defaut version\"]\n"}
'call defaut version' in repsonse shows it is the latest contract.
- Call by JavaScript
//Call HelloWorld get
var result = web3sync.callByNameService("HelloWorld","get","",[]);
//Call HelloWorld v-1.0 get
var result = web3sync.callByNameService("HelloWorld","get","v-1.0",[]);
//Call HelloWorld set sendRawTransaction
var result = web3sync.sendRawTransactionByNameService(config.account,config.privKey,"HelloWorld","set","",["test message!"]);
//Call HelloWorld v-1.0 set sendRawTransaction
var result = web3sync.sendRawTransactionByNameService(config.account,config.privKey,"HelloWorld","set","v-1.0",["test message!"]);
Appendix One: Function overload¶
Solidity supports function overload. The value format of input ‘func’ parameter is different than original when calling overloaded function:
//file : OverloadTest.sol
pragma solidity ^0.4.4;
contract OverloadTest {
string public msg;
uint256 public u;
function OverloadTest() {
msg = "OverloadTest Test";
u = 0x01;
}
function set(string _msg) public {
msg = _msg;
}
function set(uint256 _u) public {
u = _u;
}
function get() public constant returns(string){
return msg;
}
function get(uint256 i) public constant returns(uint256){
return u;
}
}
In OverloadTest.sol:set function is a overloaded function, one function is set(string), the other is set(uint256).get function is also an overloaded function, one function is get(), the other is get(uint256).
Deployment Procedure:
babel-node deploy.js OverloadTest
RPC=http://0.0.0.0:8546
Ouputpath=./output/
deploy.js ........................Start........................
OverloadTest Compiled successfully!
Send transaction successfully: 0xff8a5708b3f7b335570a50639f2073e5e0b8b2002faa909dc75727059de94f4e
OverloadTest Contract address 0x919868496524eedc26dbb81915fa1547a20f8998
OverloadTest Deployed successful!
cns add operation => cns_name = OverloadTest
cns_name =>OverloadTest
contract =>OverloadTest
version =>
address =>0x919868496524eedc26dbb81915fa1547a20f8998
abi =>[{"constant":false,"inputs":[{"name":"_msg","type":"string"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_u","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"msg","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"u","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]
===>> namecall params = {"contract":"ContractAbiMgr","func":"addAbi","version":"","params":["OverloadTest","OverloadTest","","[{\"constant\":false,\"inputs\":[{\"name\":\"_msg\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_u\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"msg\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"u\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"}]","0x919868496524eedc26dbb81915fa1547a20f8998"]}
Send transaction successfully: 0x56e2267cd46fddc11abc4f38d605adc1f76d3061b96cf4026b09ace3502d2979
The overload function needs to specify the full function signature other than just the name:
When call get(), “func” is “get()”; When call get(uint256 i), “func” is “get(uint256)”;When call set(string _msg), “func” is “set(string)”;When call set(uint256 _u), “func” is “set(uint256)”;
Example:
Call get():
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"OverloadTest","version":"","func":"get","params":[]}},"latest"],"id":1}' "http://127.0.0.1:8546"
{"id":1,"jsonrpc":"2.0","result":"[\"OverloadTest Test\"]\n"}
Call get(uint256 i):
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"data":{"contract":"OverloadTest","version":"","func":"get(uint256)","params":[1]}},"latest"],"id":1}' "http://127.0.0.1:8546"
{"id":1,"jsonrpc":"2.0","result":"[\"1\"]\n"}
Call set(string _msg) by Javascript:
var result = web3sync.sendRawTransactionByNameService(config.account,config.privKey,"OverloadTest","set(string)","",["test message!"]);
jsCall set(uint256 _i)):
var result = web3sync.sendRawTransactionByNameService(config.account,config.privKey,"OverloadTest","set(uint256)","",["0x111"]);
Appendix two: RPC called by Java¶
Take HelloWorld.sol contract as an example:
- Deploy HelloWorld.sol and use the cns_manager.js to register HelloWorld to contract manager.
- Download web3sdk, the version needs >= V1.1.0.
- The HelloWorld Java wrapper (reference tutorial ) generated by web3sdk, code package - org.bcos.cns - as below:
package org.bcos.cns;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Future;
import org.bcos.channel.client.TransactionSucCallback;
import org.bcos.web3j.abi.TypeReference;
import org.bcos.web3j.abi.datatypes.Function;
import org.bcos.web3j.abi.datatypes.Type;
import org.bcos.web3j.abi.datatypes.Utf8String;
import org.bcos.web3j.crypto.Credentials;
import org.bcos.web3j.protocol.Web3j;
import org.bcos.web3j.protocol.core.methods.response.TransactionReceipt;
import org.bcos.web3j.tx.Contract;
import org.bcos.web3j.tx.TransactionManager;
/**
* Auto generated code.<br>
* <strong>Do not modify!</strong><br>
* Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>, or {@link org.bcos.web3j.codegen.SolidityFunctionWrapperGenerator} to update.
*
* <p>Generated with web3j version none.
*/
public final class HelloWorld extends Contract {
private static final String BINARY = "6060604052341561000c57fe5b5b604060405190810160405280600b81526020017f48692c57656c636f6d652100000000000000000000000000000000000000000081525060009080519060200190610059929190610060565b505b610105565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a157805160ff19168380011785556100cf565b828001600101855582156100cf579182015b828111156100ce5782518255916020019190600101906100b3565b5b5090506100dc91906100e0565b5090565b61010291905b808211156100fe5760008160009055506001016100e6565b5090565b90565b6102e2806101146000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100465780636d4ce63c146100a0575bfe5b341561004e57fe5b61009e600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610139565b005b34156100a857fe5b6100b0610154565b60405180806020018281038252838181518152602001915080519060200190808383600083146100ff575b8051825260208311156100ff576020820191506020810190506020830392506100db565b505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b806000908051906020019061014f9291906101fd565b505b50565b61015c61027d565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101f25780601f106101c7576101008083540402835291602001916101f2565b820191906000526020600020905b8154815290600101906020018083116101d557829003601f168201915b505050505090505b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023e57805160ff191683800117855561026c565b8280016001018555821561026c579182015b8281111561026b578251825591602001919060010190610250565b5b5090506102799190610291565b5090565b602060405190810160405280600081525090565b6102b391905b808211156102af576000816000905550600101610297565b5090565b905600a165627a7a723058205f78cf9b4365c5a429ff9e4ebc4abf1f9e9d44f0a41c19c85c9d394438f3fe7b0029";
public static final String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"n\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"}]";
private HelloWorld(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, Boolean isInitByName) {
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit, isInitByName);
}
private HelloWorld(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, Boolean isInitByName) {
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit, isInitByName);
}
private HelloWorld(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit, false);
}
private HelloWorld(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit, false);
}
public Future<TransactionReceipt> set(Utf8String n) {
Function function = new Function("set", Arrays.<Type>asList(n), Collections.<TypeReference<?>>emptyList());
return executeTransactionAsync(function);
}
public void set(Utf8String n, TransactionSucCallback callback) {
Function function = new Function("set", Arrays.<Type>asList(n), Collections.<TypeReference<?>>emptyList());
executeTransactionAsync(function, callback);
}
public Future<Utf8String> get() {
Function function = new Function("get",
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
return executeCallSingleValueReturnAsync(function);
}
public static Future<HelloWorld> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue) {
return deployAsync(HelloWorld.class, web3j, credentials, gasPrice, gasLimit, BINARY, "", initialWeiValue);
}
public static Future<HelloWorld> deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue) {
return deployAsync(HelloWorld.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, "", initialWeiValue);
}
public static HelloWorld load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new HelloWorld(contractAddress, web3j, credentials, gasPrice, gasLimit, false);
}
public static HelloWorld load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
return new HelloWorld(contractAddress, web3j, transactionManager, gasPrice, gasLimit, false);
}
public static HelloWorld loadByName(String contractName, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new HelloWorld(contractName, web3j, credentials, gasPrice, gasLimit, true);
}
public static HelloWorld loadByName(String contractName, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
return new HelloWorld(contractName, web3j, transactionManager, gasPrice, gasLimit, true);
}
}
Two additional loadByName methods are generated for CNS call.
- Call the method by contract name
package org.bcos.main;
import java.math.BigInteger;
import java.util.concurrent.Future;
import org.bcos.channel.client.Service;
import org.bcos.cns.HelloWorld;
import org.bcos.web3j.abi.datatypes.Utf8String;
import org.bcos.web3j.crypto.Credentials;
import org.bcos.web3j.crypto.ECKeyPair;
import org.bcos.web3j.crypto.Keys;
import org.bcos.web3j.protocol.Web3j;
import org.bcos.web3j.protocol.channel.ChannelEthereumService;
import org.bcos.web3j.protocol.core.methods.response.TransactionReceipt;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//init service
Service service = context.getBean(Service.class);
ChannelEthereumService channelEthereumService = new ChannelEthereumService();
channelEthereumService.setTimeout(10000);
channelEthereumService.setChannelService(service);
//init web3
Web3j web3j = Web3j.build(channelEthereumService);
service.run();
//init private key
ECKeyPair keyPair = Keys.createEcKeyPair();
Credentials credentials = Credentials.create(keyPair);
BigInteger gasPrice = new BigInteger("99999999");
BigInteger gasLimit = new BigInteger("99999999");
//Use CNS call the contract when the contract is created by loadByName.
HelloWorld instance = HelloWorld.loadByName("HelloWorld", web3j, credentials, gasPrice , gasLimit);
//Call HelloWorld set
Future<TransactionReceipt> receiptResult = instance.set(new Utf8String("HelloWorld Test."));
receiptResult.get();
//Call HelloWorld get
Future<Utf8String> result = instance.get();
System.out.println("HelloWorld get result = " + result.get().toString());
return;
}
}
CNS can be used to call contract function if the contract instance created by loadByName.
HelloWorld instance = HelloWorld.loadByName("HelloWorld", web3j, credentials, gasPrice , gasLimit);
The ‘get’ and ‘set’ functions are called by CNS as the contract instance is created by loadByName.
- P.S.:The Java wrapper method - loadByName - is generated by XX.sol as follows:
public static XX loadByName(String contractName, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new XX(contractName, web3j, credentials, gasPrice, gasLimit, true);
}
public static XX loadByName(String contractName, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
return new XX(contractName, web3j, transactionManager, gasPrice, gasLimit, true);
}
The value format of contractName input parameter is: contractName@version, version is optional.
- Summary
- Use JavaScript tool to deploy contracts.
- Use cns_manager.js tool to register a contract to contract manager.
- Use websdk tool to generate Java wrapper.
- Add the Java wrapper to project and create the contract by loadByName.
- Call the contract function.
Permission Model¶
Author: fisco-dev
Introduction to Permission Model - ARPI¶
Unlike public chain which anyone can access, transact and search, the consortium chain has the specific entry requirements, such as access control, various transactions support, privacy & security,high stablity etc. There are two key aspects in the consortium chain: “permission” and “control”
The permission model ARPI(Account—Role—Permission—Interface) is based on the thought of system level permission and interface level permission.
System level permission controls whether an account can deploy or call a contract. When a request is received, the system will check the sender’s permissions and will permit or reject accordingly. Interface level permission controls whether an account can call a specific interface of a contract. The admin can give an account the permissions to call all or part of the interfaces of a contract.
In the ARPI model, there are 4 objects - Account, Role, Permission and Interface, their relationship is as below:
Account : Role -> N : 1
An account (person or organization) can only have one specific role, but a role can be assigned to zero or more accounts. In practice, a role may have multiple accounts with different pair of public and private keys for each,when a transaction starts, the sender signs the transaction with its private key, and then the receiver can verify it by using sender’s public key to know which account the transaction was initiated from, so that the transaction can be controlled and traced.
Role : Permission -> N : N
A role can have multiple permissions and a permission can also be assigned to multiple roles. You can have fine granularity of permission control under the ARPI model. You can set permission to the contract’s interfaces.
ARPI objects relationship is as below:
ARPI Framework Implementation¶
TransactionFilterChain contract is deployed along with the system proxy contract during initialization, and it is registered by system proxy contract at the same time. All the permissions’ CRUD is maintained by TransactionFilterChain on a blockchain. When a request is received, the system will check whether the sender’s account has permissions to the corresponding operations, if yes, then it is executed, otherwise exception is thrown.
ARPI process flow as below:
Two general types of permissions:
- Deploy contract, only the approved contract can be deployed on the chain for execution.
- Call contract, only the permitted accounts can call the corresponding interfaces of the contract to execute their business transactions.
Process flow details:
- TransactionFilterChain includes multiple independent filters with it’s specific filtering logic. An account will have the specific permissions if it passes all filters’ validation. A filter can be managed by a member of the consortium and the permissions can be added independently.
- Each filter has a switch, the filter is effective only when it is switched on. By default, filter is switched off during the initialization.
- There are different groups within the filter, when the filter is executed, corresponding group (with it’s permissions) is found based on the sender’s account.
- The Group contains the permissions of deploying contract or calling contract. For deploying a contract only one input sender’s address is needed, whereas for calling a contract four inputs sender’s address, contract address, function and the parameters are required. By default, the group does not have the permission for deploying the contract during initialization.
- It is possible to configure black list validation which can be effective while calling a contract. If the black list mode is on, no permission will be returned, if the user was added into the black list, even though an account has the permission for an interface. By default, the black list mode is off.
- An interface is comprised of a function along name with its parameters.
- The address changes once a contract gets redeployed, so the permissions of the contract need to be re-granted.
ARPI practice on consortium chain¶
Roles and Permissions are generally related to scenarios, there will have different roles and permissions design based on different business requirement. Based on the practice on FISCO BCOS, here let’s list out the definitions of roles and permissions for reference:
- Chain Super Admin (God account)A chain super administrator is selected by the consortium committee or public, who has all the permissions to the system. This role has following permissions: assign roles to users, add permissions to roles, which includes the permissions to perform any operations. The God account is required to execute the system contracts.
- Chain/Filter adminA chain/filter administrator can manage filters and audit, modify and delete information of nodes, accounts and contracts on the chain. This role has following permissions: execute the system contracts – CAAction, NodeAction, ContractABIAction and SystemProxy.
- Operation adminAn operation administrator is a person who deploys/manages the non-system contracts and nodes configuration, but doesn’t participate in business transactions. This role has following permissions: execute ConfigAction, deploy non-system contracts (except for SystemProxy, which is needed to get ConfigAction). For the non-system contracts, chain manager needs to call ContractABIAction to make the contract effective (this call can be made by contract name rather than by address)
- TraderA Trader is a person who uses the system to conduct business transactions and query the results, the role here can be subdivided based on different business requirements. This role has following permissions: execute and query business contracts.
- Chain regulator (Optional to be a group)A regulator is a person who is responsible for setting up the permission specifications. The person usually is not participant in the chain’s management but can participant in the business transactions. This role has following permissions: trace the operation records (The inputs for deploying and calling the contracts will be recorded by Event notification, which can be used for audit purposes)
Script Usage Guidelines¶
ARPI_Model.js located under folder systemcontract, provides one step execution to start the ARPI mode which includes enabling access control and setting up the roles and permissions according to the previous section ARPI practice on consortium chain.
Note: The access control will be enabled after executing ARPI_Model.js, you can be disabled by using the GOD account, to avoid impacting other accounts to deploy or call contracts accidently.
AuthorityManager.js located under the same folder systemcontract, used to manage TransactionFilterChain and provides the query interfaces to FilterChain, Filter, and Group.
Note: AuthorityManager.js and ARPI_Model.js execution requires God account.
- FilterChain can be obtained without index. FilterChain provides the functions to add, delete, show and reset a filter on the chain. The commands are as below:
babel-node AuthorityManager.js FilterChain addFilter <filter's name><version><description>
babel-node AuthorityManager.js FilterChain delFilter <filter's index>
babel-node AuthorityManager.js FilterChain showFilter
babel-node AuthorityManager.js FilterChain resetFilter
- Filter can be obtained with its index from FilterChain. Filter provides the functions 1) to enable, disable and display status of a filter. 2) to add an account to a new or existing group. 3) to display the group of the given account. The commands as below:
babel-node AuthorityManager.js Filter getFilterStatus <filter's index>
babel-node AuthorityManager.js Filter enableFilter <filter's index>
babel-node AuthorityManager.js Filter disableFilter <filter's index>
babel-node AuthorityManager.js Filter setUsertoNewGroup <filter's index> <user's account>
babel-node AuthorityManager.js Filter setUsertoExistingGroup <filter's index> <user's account> <group's address>
babel-node AuthorityManager.js Filter listUserGroup <filter's index> <user's account>
- Group can be obtained with the filter’s index in the FilterChain and it’s binding user’s account. Group provides the functions to maintain its permission list, enable/disable the permission for deploying contract and verifying black list. The commands as below:
babel-node AuthorityManager.js Group getBlackStatus <filter's index> <user's account>
babel-node AuthorityManager.js Group enableBlack <filter's index> <user's account>
babel-node AuthorityManager.js Group disableBlack <filter's index> <user's account>
babel-node AuthorityManager.js Group getDeployStatus <filter's index> <user's account>
babel-node AuthorityManager.js Group enableDeploy <filter's index> <user's account>
babel-node AuthorityManager.js Group disableDeploy <filter's index> <user's account>
babel-node AuthorityManager.js Group addPermission <filter's index> <user's account> <contract address> <func name(parameters)>
babel-node AuthorityManager.js Group delPermission <filter's index> <user's account> <contract address> <func name(parameters)>
babel-node AuthorityManager.js Group checkPermission <filter's index> <user's account> <contract address> <func name(parameters)>
babel-node AuthorityManager.js Group listPermission <filter's index> <user's account>
- Prompt for missing the permissions
The following error is raised if no permission to deploy a contract:Transaction failed to send! Error: NoDeployPermission .
The following error is raised if no permission to call a contract:Transaction failed to send! Error: NoTxPermission .
OrError: NoCallPermission .
- An example for using AuthorityManager.js as below (to avoid unexpected exception, please ensure the account configured in config.js is the God account)
//Add a filter to FilterChain with 3 parameters – filter name, version and description.
babel-node AuthorityManager.js FilterChain addFilter NewFilter 2.0 FilterUsedForTest
//Delete a filter from FilterChain with its index
babel-node AuthorityManager.js FilterChain delFilter 1
//Display all filters on FilterChain
babel-node AuthorityManager.js FilterChain showFilter
//Reset FilterChain to its initialize status
babel-node AuthorityManager.js FilterChain resetFilter
//Display a filter's status with its index
babel-node AuthorityManager.js Filter getFilterStatus 1
//Enable a filter with its index
babel-node AuthorityManager.js Filter enableFilter 1
//Disable a filter with its index
babel-node AuthorityManager.js Filter disableFilter 1
//Grant a new role(group) to an account with two parameters – filter's index and user's account
babel-node AuthorityManager.js Filter setUsertoNewGroup 0 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
//Grant an existing role(group) to an account with 3 parameters – filter's index, user's account and group's address (the group's address is getting from command 'listUserGroup' after the group have been created by command 'setUsertoNewGroup')
babel-node AuthorityManager.js Filter setUsertoExistingGroup 0 0x6ea2ae822657da5e2d970309b106207746b7b6b3 Group.address
//Display the role(group) of an user's account with 2 parameters – filter's index and user's account
babel-node AuthorityManager.js Filter listUserGroup 0 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Display the status of black list mode with 2 parameters – filer's index and group's address
babel-node AuthorityManager.js Group getBlackStatus 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Enable black list validation with 2 parameters – filer's index and group's address
babel-node AuthorityManager.js Group enableBlack 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Disable black list validation with 2 parameters – filer's index and group's address
babel-node AuthorityManager.js Group disableBlack 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Display the permission status of deploying contract with 2 parameters - filer's index and group's address
babel-node AuthorityManager.js Group getDeployStatus 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Enable the permission of deploying contract with 2 parameters - filer's index and group's address
babel-node AuthorityManager.js Group enableDeploy 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Disable the permission of deploying contract with 2 parameters - filer's index and group's address
babel-node AuthorityManager.js Group disableDeploy 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
// Add the permissions to a group with 4 parameters - filer's index and group's address, contract's address and contract's interface
>Note: the contract's address here is the real address rather than the DNS name, so the permission need to be re-granted if the contract get re-deployed
babel-node AuthorityManager.js Group addPermission 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9 ContractA.address "set1(string)"
//Delete the permissions from a Group with 4 parameters - filer's index and Group's address, contract's address and contract's interface
babel-node AuthorityManager.js Group delPermission 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9 ContractA.address "set1(string)"
//Check if the permissions of a Group exist with 4 parameters - filer's index and Group's address, contract's address and contract's interface
babel-node AuthorityManager.js Group checkPermission 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9 ContractA.address "set1(string)"
//List the permissions of a group with 2 parameters - filer's index and group's address
babel-node AuthorityManager.js Group listPermission 1 0x4015bd4dd8767d568fc54cf6d0817ecc95d166d9
Group signature and Ring signature¶
Author: fisco-dev
1 Introduction¶
Group-Signature has the feature of tamper-resistant, repudiation-resistant, anonymity and traceability. It can be used in many scenarios.
1.1 Application Scenarios¶
(1) Group signature Scenarios
- First Scenario(acution, anonymous deposits):The users or the sub-institutions of specified institution publish their data (such as evidence, encrypted-biding) on the blockchain, but they don’t want to reveal their identities while to ensure the authority of the data with signatures. In this case, the group-signature algorithm will come in handy. They can sign the data by using the group-signature algorithm with a private key issued by the administrator of the institution. Other people can verify the validity of the data using a common public key issued by the administrator of the institution when accessing the data, while can’t figure-out the concrete identity of the signers. In this scenario, privacy and anonymity are guaranteed when put data in the block-chain.
- Second Scenario (Privacy-Reveal Service for Regulators):The group-signature algorithm has the feature of traceability. The group administrator of specified group can reveal the signer of specified signature using its private key. This feature is very useful for the regulators by revealing the identity of given signature to trace illegal transactions. The regulators can trace the signers of illegal transactions through group administrator.
(2) Ring signature Scenarios
- First Scenario (Anonymous voting):Members (Consumer user) in the organization signs the vote and place the signature on the blockchain via the trusted agent(such as webank), When verifiers verifies the ring signature, they can only identify the individual agent the signature belongs to, but cannot trace the signers(voter).
- Second Scenario(Anonymous deposit, credit checks etc.):The scenario is similar to group signature’s anonymous deposit scenario, but the difference is that nobody can trace the signer of the given signature.
- Third Scenario(Anonymous transaction):The ring signature algorithm can be used to send anonymous transactions, and no one can trace the sender and receiver of the transaction.
1.2 Source Code Structure¶
The table below descripts the source code structure of group-signature algorithm and the ring-signature algorithm:
Module | path | Description |
---|---|---|
Shell Scripts for dependencies install | scripts/install_pbc.sh & deploy_pbc.sh | pbc and pbc-sig lib are used for group signature,install the pbc and pbc-sig by calling deploy_pbc.sh |
source code for group signature & ring signature | deps/src/group_sig_lib. tgz | source code for group signature & ring signature |
Compile Module | cmake/FindPBC.cmake & cmake/ProjectGroupSig.cma ke | compile cmake file related to group signature & ring signature |
Verification implement | libevm/ethcall/EthcallGro upSig.h & libevm/ethcall/EthcallRin gSig.h | use ethcall to call the group/ring signature lib |
FISCO BCOS supports configuring to enable or disable the ethcall for group signature & ring signature ( default is disabled).
Action | Compile | Compile time | Description |
---|---|---|---|
enable ethcall | dependencies will compile | long compile time | group/ring signature enabled |
disable ethcall | dependencies will not compile | short compile time | group/ring signature disabled |
2 Deployment¶
Ensure that FISCO BCOS is deployed before deploying ethcall. (How to deploy FISCO BCOS )
Enable/Disable ethcall for group signature and ring signature¶
(1) Install dependencies
① Install basic dependencies
Install git, dos2unix and lsof before deploying FISCO BCOS:
- git: get the latest code
- dos2unix && lsof
Use below commands to install these dependencies: (If installation fails, check the configuration of yum and ubuntu)
[centos]
sudo yum -y install git
sudo yum -y install dos2unix
sudo yum -y install lsof
[ubuntu]
sudo apt install git
sudo apt install lsof
sudo apt install tofrodos
ln -s /usr/bin/todos /usr/bin/unxi2dos
ln -s /usr/bin/fromdos /usr/bin/dos2unix
② Install pbc and pbc-sig for group signature
Install pbc and pbc-sig before using ethcall for group signature,FISCO BCOS provides pbc and pbc-sig deploy scripts(both centos and ubuntu OS are supported):
# Use dos2unix to format script, in case the Windows files upload to Linux cannot be parsed correctly
bash format.sh
# Use deploy_pbc.sh script to install pbc and pbc-sig
sudo bash deploy_pbc.sh
(2) Enable/disable ethcall for group/ring signature
FISCO BCOS group/ring signature use ‘-DGROUPSIG=ON’ or ‘-DGROUPSIG=OFF’ to control whether need compile, default ‘-DGROUPSIG=OFF’.
Enable:
# create build file for store the compiled file
cd FISCO-BCOS && mkdir -p build && cd build
# enable group/ring signature when cmake create Makefile
#**centos OS:
cmake3 -DGROUPSIG=ON -DEVMJIT=OFF -DTESTS=OFF -DMINIUPNPC=OFF ..
#**ubuntu OS:
cmake -DGROUPSIG=ON -DEVMJIT=OFF -DTESTS=OFF -DMINIUPNPC=OFF ..
Disable:
# create build file for store the compiled file
cd FISCO-BCOS && mkdir -p build && rm -rf build/* && cd build
# disable group/ring signature when cmake create Makefile
#centos OS:
cmake3 -DGROUPSIG=OFF -DEVMJIT=OFF -DTESTS=OFF -DMINIUPNPC=OFF ..
#ubuntu OS:
cmake -DGROUPSIG=OFF -DEVMJIT=OFF -DTESTS=OFF -DMINIUPNPC=OFF ..
(3) Compile and start FISCO BCOS
# compile fisco-bcos
make -j4 #Note: j4 stand for use 4 threads complicating compile, can be configured as needs.
# start fisco-bcos:
bash start.sh
Other dependencies¶
(1) Client application: sig-service-client
sig-service-client provides below features:
- Access sig-service rpc interface.
- Place signature on the blockchain(by performing a transaction)
Usage and deployment details Group signature & Ring signature client guidebook.
(2) group signature and ring signature service:sig-service
sig-service is deployed in the organization and provides below features for sig-service-client:
- Create Group, add group member, generate group signature, verify group signature, trace signatory’s identity.
- Create Ring, generate ring signature, verify ring signature.
In FISCO BCOS, sig-service-client always requests a group/ring signature first, then places the signature on the blockchain. Blockchain nodes verify the signature by invoking ethcall.
sig-service’s usage and deployment details group signature & ring signature RPC guidebook.
3 Note¶
(1) Group signature & ring signature is backward compatible
(2) After enabling ethcall, you cannot stop ethcall service
If ethcall is stopped by mistake, FISCO BCOS can be reverted back to the version used to enable the ethcall.
(3) The version of all nodes deploy FISCO BCOS must be consistent
If a node enables group/ring signature verification service, then all the other nodes must enable it as well. Otherwise the nodes which have not enabled verification service will be exit abnormally.
(4) Before invoking group/ring signature verification service, you must deploy group signature & ring signature RPC guidebook and sig-service-client
sig-service-client responsible for placing the signature on the blockchain,group signature & ring signature RPC guidebook responsible for providing signature generating service
Parallel PBFT¶
Author: fisco-dev
1. Glossary¶
Blockchain:¶
Blockchain is a growing list of records, called blocks, which are linked using cryptography. Each block contains current block data and a cryptographic hash of the previous block. There are two key concepts in blockchain: cryptography and decentralization. These two key concepts are used to ensure that the block data cannot be tampered with.
A block consists of block head and block body. The block head contains the block height(h), previous block hash(prevHash) etc., and the block body mainly contains transaction data.
P2P(peer-to-peer) network:¶
Unlike traditional centralized networks, P2P networks is that participants make up a network through P2P protocols, and participants are peers. P2P network has the following advantages:
- Decentralization: No need of centralized server, resources and servers are separated on nodes and all the data transfers and services happen between nodes.
- Robustness: Nodes joining or quitting the blockchain does not impact network services.
- Extensibility: Supports extensibility of the system by increasing the number of nodes. For example, based on the P2P file download protocol, as more users join, speed for download becomes faster.
- Cost-effectiveness: In the P2P network, the nodes are generally ordinary machines. Industry level service provisioning is achieved through use of network system built upon ordinary machines with brings considerable cost advantage.
Node:¶
In a P2P network, every participant is a node and the nodes constitute the blockchain. In a blockchain P2P network, a node is a uniquely-identified participant with a complete ledger copy, and participates in consensus and account maintenance.
Consensus algorithm:¶
Every node in the blockchain P2P network confirms a batch of transactions by an algorithm and ensures that all nodes have consistent confirmation results for the batch of transactions. This algorithm is called blockchain consensus algorithm.
Byzantine Fault Tolerance(BFT):¶
Byzantine fault tolerance comes from the Byzantine general problem. In a P2P network system, where nodes may run in any form without restrictions and may unite to perform malicious actions. As long as the number of such malicious nodes is within a certain range, the system still continues functioning properly, and the system is called Byzantine fault tolerant system.
2. Brief to existing consensus algorithm¶
2.1 Existing consensus¶
The existing consensus algorithms of blockchain mainly include Proof of Work(POW), Proof of Stake(POS), Delegated Proof of Stake(DPOS) and Practical Byzantine Fault Tolerance(PBFT). Among consensus algorithms, POW, POS, DPOS are mainly used for public chains like bitcoin, but PBFT is used for traditional distributed systems, which accomplishes the consensus algorithm through three rounds of broadcast communication.
2.2 Insufficient calculation of existing consensus algorithm¶
- POW builds consensus through computation, so it causes a lot of energy consumption and also inconsistent block generation time.
- POS and DPOS build consensus by using tokens, which might easily cause the tokens to be centralized, so the consensus is controlled by a few, and they can unite to perform malicious actions to destroy the network;
- PBFT algorithm consists of three phases which are serially executed so consensus efficiency is low.
3. Parallel Practical Byzantine Fault Tolerance Consensus Algorithm¶
3.1 Node Roles¶
- Leader node: Leader packages and broadcasts the block to other nodes. Transactions in the block are verified by consensus algorithm and after verification the block height will increase.
- Follower node: Followers receive block from the leader node and confirm whether the transaction is valid, followers will sign the signature to the block when the nodes agree on a block, then the consensus process is done.
3.2 Node’s role transition¶
In PBFT, node’s role is changed as time goes by.
As we know that blockchain is built up by nodes, assume that there are N nodes totally, and each node has a unique index: Idx(i), and node’s role is decided by a formula: (h+v)%N, where h is the current block height, and v is the current view(more information about view in section 3.4 Exception handling).
3.3 Consensus decision-making¶
Consensus decision-making is the process of blockchain network confirming a batch of transactions and achieving network-wide consensus. Consensus decision-making has following steps:
- Leader election: The algorithm mentioned in section 3.2 is used to elect a leader. In case of FISCO BCOS, a patented algorithm is used to elect leader through consensus process, which is much more efficient compared to the traditional algorithms.
- Package transaction: Leader packages and creates a new block, then broadcasts the block to other nodes.
- Sign: Followers receive block from the leader node and confirm whether the transaction is valid, followers will sign the signature to the block when the nodes agree on a block.
- Vote: If more than 2/3 of all nodes sign the transaction, then the transaction is broadcasted.
- Data to disk: If more than 2/3 of all nodes vote, then the data is stored to disk.
3.4 Exception handling¶
In the several stages of the consensus decision-making process described in section 3.3, each stage may not be able to work smoothly due to reasons such as error, timeout or deliberate malicious activities and may fail the consensus decision-making process. FISCO BCOS uses a patented algorithm which solves this problem through introduction of an exception handling process. The whole process of a consensus is defined as a view, and all stages need to be completed in the same view.
When a node completes storing block h to disk, it needs to start the consensus process of block h+1. At this time, a timer will be set for consensus process of block h+1. If the consensus process is not completed before timeout, it will execute the view-change process.
First, view-change process will execute v++, and then broadcast v to all the nodes. If more than 2/3 nodes receive the same view v change request, then it will switch to the next view.
3.5 Parallel computing¶
In the consensus process (introduced in section 3.3), the processes of leader node package transaction and follower node verify transaction are the most time-consuming parts of the entire consensus process, and these two processes are executed serially. Assumed that the transaction confirmation time is T, and the total process consumption time is T’, so the time spent on the whole consensus is 2*T+T’. FISCO BCOS patent consensus algorithm proposes an improved design for the parallelization of the transaction confirmation mechanism, and the overall consensus time is reduced to T+T’, which greatly improves the consensus efficiency.
Regulated Zero-knowledge proof¶
Author: fisco-dev
To meet the regulatory requirements, FISCO BCOS provides a framework to perform anonymous transactions by zero-knowledge proof, it also satisfies the regulatory requirement that regulators can regulate every transaction.
1. Glossary¶
Zero-knowledge proof: Let you validate the truth of something without revealing how you know that truth or sharing the content of this truth with the verifier.
Zero-knowledge proof on blockchain: A proof, derived from the user data, to be verified by the blockchain nodes to prove that the user knows the secret information, and the proof itself cannot be reverted back to the original data. It helps the node to verify the user data’s correctness without having knowledge of any part of the original data. So zero-knowledge proof provides a way to perform secret transactions using blockchain, although there exists a regulatory risk.
FISCO-BCOS regulated Zero-knowledge proof: FISCO BCOS node works as verifier for all secret transactions (implemented by zero-knowledge proof) on the chain. While all transactions can be ONLY decrypted/overseen by authorized regulator.
2. Underlying library¶
3. Case study¶
(1) Regulated one-to-one anonymous transfer
In FISCO BCOS, one-to-one anonymous transfer can be verified by the blockchain nodes without knowing receiver’s and sender’s identities and amount. In the meantime, regulator can decrypt the anonymous transfer. More details:zkg-tx1to1
(2) Coming soon…
System Contract Introduction¶
Author: fisco-dev
Design Overview¶
In order to meet the requirements of access control, identity authentication, configuration management and permissions management etc., FISCO BCOS will deploy a set of powerful, flexible, and custom-defined smart contracts during the network initialization, collectively referred to as system contracts.
The system contract is deployed by administrator during initialization. For redeploying any changes or upgrades while the network is running, it is necessary for the blockchain administrator to get an agreement of all the nodes within the network.
FISCO BCOS system contract is comprised of five modules: System Proxy, Node Management, CA Management, Permissions Management and Configuration Management. System contracts is extendable and can be called by both core system and DAPP. There could be one or more smart contracts in a module. The modules are as below:
module structure
How it works¶
Code path: systemcontractv2/. Brief of each module is as below:
System Proxy¶
SystemProxy.sol, the system proxy’s implementation, provides a mapping between route and contract address, unified system contract interface. In SystemProxy.sol, routing info is held by a mapping field, named as ‘_routes’. The value of mapping is structured as below:
struct SystemContract {
address _addr; #contract address
bool _cache; #cache flag
uint _blocknumber; #block height when the contract is active
}
Key functions:
function | input parameters | output parameters | description |
---|---|---|---|
getRoute | string key#route name | address#contract address, bool#catch flag, uint # block height | get route information |
setRoute | string key#route name, address addr#contract address, bool cache#cache flag, unit blocknumber #block height | N/A | set route, overwrite if route name exists |
Node Management¶
NodeAction.sol is the implementation contract of the node management module. It implements the function of registering, managing and maintaining the list information of all nodes in the network. Every time a node in the network joins or quits, it must controlled by the node management contract. Three node types: Core, Full, and Light.
enum NodeType{
None,
Core,
Full,
Light
}
Structure for node information:
struct NodeInfo{
string id;
string ip;
uint port;
NodeType category;
string desc;
string CAhash;
string agencyinfo;
uint idx;
uint blocknumber; #block height
}
Key functions:
function | input parameters | output parameters | description |
---|---|---|---|
registerNode | string _id string _ip uint _port NodeType _category string _desc string _CAhash string _agencyinfo uint _idx | bool #result | register node Ignore if the node exists |
cancelNode | string _id | bool #result | cancel node Ignore if the node not exists |
CA Management¶
CAAction.sol is the implementation contract of the CA management module. It provides nodes’ certificate registration, management and maintenance. Node joins or quits the chain must controlled by CA management contract if certificate verification enabled.
Structure for certificate data:
struct CaInfo{
string hash; #certificate hash
string pubkey; #certificate public key
string orgname; #organization name
uint notbefore; #certificate effective date
uint notafter; #certificate expire date
CaStatus status; #certificate status
string whitelist; #IP whitelist
string blacklist; #IP blacklist
uint blocknumber; #block height
}
Key functions:
function | input parameters | output parameters | description |
---|---|---|---|
update | string _hash string _pubkey string _orgname uint _notbefore uint _notafter CaStatus _status string _whitelist string _blacklist | bool #result | update certificate create certificate if certificate not exists |
get | string _hash | string#certificate hash string#certificate public key string#organization name uint#certificate effective date uint#certificate expire date CaStatus#certificate status uint##block height | get certificate information |
Permissions Management¶
Permissions management’s design principles: 1, One external account only belongs to one role. 2, One role only has one permission list. 3, Permission is identified by a combination of function and its contract address.
Permission module are comprised of 4 contracts: TransactionFilterChain.sol, TransactionFilterBase.sol, AuthorityFilter.sol, Group.sol.
TransactionFilterChain.sol, the implementation of Filter pattern, provides a unified function ‘process’ for permission checking. It holds an address list of Filter contract which extends from TransactionFilterBase. All permissions will be checked by the calling ‘process’ function of each Filter contract sequentially.
All Filters must implement TransactionFilterBase’s ‘process’ interface, AuthorityFilter is inherited from TransactionFilterBase’s role permission Filter implementation. Its process interface implements the checking logic for the permissions of the user role groups.
Group.sol handles the concept of Role. It internally maintains the mapping flag for all permission entries for this role.
Key functions:
contract | function | input parameters | output parameters | description |
---|---|---|---|---|
TransactionFilterBase | process | address origin #external address address from#from account address address to#to account address string func#contract address string input#transaction input | bool#result | permission checking |
Group | setPermission | address to#to account address string func#contract address bool permission#permission flag | bool#result | set permission |
Configuration Management¶
ConfigAction.sol is the implementation of configuration management module for entire network. It maintains configurable information for the entire network in the FISCO BCOS blockchain. The configuration information is kept consistent through out the entire network by transactions broadcast. In principle, only the blockchain administrator can issue transactions broadcast to perform network-wide configuration changes.
Key functions:
function | input parameters | output parameters | description |
---|---|---|---|
set | string key #parameter string value#config information value | N/A | set configuration |
get | string key #parameter | string #config information uint#block height | get configuration |
key parameters:
parameter | description | default value | recommend value |
---|---|---|---|
maxBlockHeadGas | Gas spend limitation for each block (Hex) | 200000000 | 20000000000 |
intervalBlockTime | an interval btw block generation(ms) (Hex) | 1000 | 1000 |
maxBlockTranscations | configure the max transaction in a block(Hex) | 1000 | 1000 |
maxNonceCheckBlock | Trace back max previous block number to avoid nonce duplication.(Hex) | 1000 | 1000 |
maxBlockLimit | max delay for transaction commit(Hex) | 1000 | 1000 |
maxTranscationGas | Gas spend limitation for each transaction(Hex) | 20000000 | 20000000 |
CAVerify | CA verification flag | FALSE | FALSE |
Customizations¶
Example 1 - Custom Business Contract¶
To customize a business contract by modifying business configuration. Refer to the steps below:
- Implement ‘set’ and ‘get’ based on business requirement.
- Deploy business contract and get contract address.
- Call the ‘setRoute’ method in SystemProxy to register contract address in the routing table.
- Business smart contract is now ready to be called.
How to call the business contract:
- Call the ‘getRoute’ method in SystemProxy to get the contract address.
- Get configured information by calling the ‘get’ method with address in step 1.
Example 2 - Custom Permission Contract¶
Permission checking can be extended by adding new Filter. Refer to the steps below:
- Create a Filter permission contract by inheriting TransactionFilterBase. The custom permissions verification logic should be implemented into the ‘process’ interface as per the business requirements.
- Deploy custom permission contract and get contract address.
- Call the ‘getRoute’ method in SystemProxy to get contract address of TransactionFilterChain.
- Register custom filter contract by calling ‘addFilter’ method in TransactionFilterChain.
- The contract is now ready for calling.
System Configuration¶
Author: fisco-dev
Design Overview¶
There are many distributed nodes in a block chain. To ensure the configuration is in sync on all nodes, a mechanism has been built in FISCO BCOS using smart contract to sync up the configuration across all nodes:
reference
System Properties¶
maxBlockTranscations¶
Description: configure the max transaction in a block
Value: (0,2000]
Default: 1000
maxTranscationGas¶
Description: Gas spend limitation for each transaction
Value: >= 30,000,000
Default: 30,000,000
maxNonceCheckBlock¶
Description: Trace back max previous block number to avoid nonce duplication.
Value: >= 1000
Default: 1000
omitEmptyBlock¶
Description: skip empty blocks (will not store the block when there is no transaction)
Value: true/false
Default: true
update configuration¶
Configuration can be updated by calling system contract on any node but using genesis node is recommended.
Command to update configuration:
babel-node tool.js ConfigAction set [parameter] [value]
Command to get configuration:
babel-node tool.js ConfigAction get [parameter]
An example to change block generation interval
cd tools/systemcontract;
babel-node tool.js ConfigAction set intervalBlockTime 1000
allow to commit empty block
cd tools/systemcontract;
babel-node tool.js ConfigAction set omitEmptyBlock false