9th March 2018
A blockchain is a continuously growing electronic ledger of transactions called 'blocks', which are linked like a 'chain' and cryptographically secured. Each block contains transactions, a timestamp and a pointer linking it to a previous block; and is inherently resistant to modification of the data. Please refer to our White Paper for a full description of the rationale and concepts for using private blockchains with the GM-X ERP application. This paper also provides a detailed description of the GM-X ERP application's built-in blockchain capabilities.
This document shows how to install the Blockchain subsystem into a GM-X installation. This will allow certain events on one GM-X instance to be transmitted to other instances so that the event can be duplicated on those instances. It requires the following components:
blockchain/sql/<dbms>/blockchain-schema.sql
.It is also important that your version of PHP has the following extensions loaded:
The following steps are required to create a private blockchain which will allow two or more nodes to communicate with each other:
If your installation is joining an existing blockchain then skip to Joining an existing blockchain.
The following steps require you to execute various MultiChain programs from the command line. You can do this by opening a command prompt in the folder in which you installed the Multichain software. Alternatively you can add the path to this folder in the PATH environment variable. In the following examples the installation folder is shown as E:\Program Files\MultiChain.
First, create the chain using the command shown in Figure 1 where <chain> is the chain identity. The following examples use the value "chain1".
Figure 1 - Use command "multichain-util create <chain>" to create the blockchain
E:\Program Files\MultiChain>multichain-util create chain1 MultiChain 1.0.2 Utilities (latest protocol 10009) Blockchain parameter set was successfully generated. You can edit it in C:\Users\Tony\AppData\Roaming\MultiChain\chain1\params.dat before running multichaind for the first time. To generate blockchain please run "multichaind chain1 -daemon".
Note here that it shows the directory where the blockchain data, including its database, will be stored. The location of the default directory depends on your operating system:
In this example it is: C:\Users\Tony\AppData\Roaming\MultiChain\<chain>\. There will be a separate <chain> directory for each chain that you create or join. Note that the blockchain database, which is non-relational, is separate from the GM-X database and can only be accessed using a small set of simple APIs and not the sophisticated SQL queries which are available in a relational database.
After a new blockchain has been created, the next step is to configure its consensus protocol.
Important: This must be done before you start the blockchain, and before any other nodes join the blockchain. Consensus protocol settings cannot be changed after a blockchain is started.
Whenever new messages are published to a blockchain, they are broadcast to all the nodes in the network, and are added to a transaction pool at each node. However, before they can be received into the GM-X instance at any of those nodes, they need to be validated first. The validation process, known as "mining", is a protocol for achieving global consensus on the validity of messages in the blockchain database. Mining is the responsibility of "miners", which are the nodes having permission to mine.
Because GM-X blockchains are private and permissioned networks, mining is a formality for forming and digitally signing blocks containing new messages. No proof of work (PoW) is required; therefore no special equipment utilising processors such as application-specific integrated circuits (ASICs) is needed. GM-X Blockchain Servers are capable of processing up to 1,000 transactions per second on a network of standard mid-range servers.
Each miner batches new messages from its transaction pool into blocks that are cryptographically hashed in a Merkle Tree using a secure hash algorithm (SHA). Next, a block header is formed from the resulting transaction root (root of the Merkle Tree), current timestamp, minimum bits (8 by default), nonce (always zero) and the hash of the previous block, which links the block to its immediate predecessor. The block header is hashed and then the miner's digital signature is added to the block header, to prove who created the block.
Digital signatures are generated by the Elliptic Curve Digital Signature Algorithm (ECDSA) using the hash of the block header, together with the private key generated for the miner's blockchain address when the miner created or joined the blockchain. Note that the private key used for signing new blocks is not the same as a private key used for sending and receiving private messages.
The first miner to complete the verification process for a block will broadcast the block to all the other nodes in the network. The GM-X Blockchain Server at each node attempts to reproduce a hash of the block header which matches the value found in the block. It also attempts to verify the miner's digital signature using a unique ECDSA property which allows the miner's public key to be calculated from the digital signature and the hash of the block header. Successful verification proves that the data in the block is genuine. It also proves that the node which mined the block was in possession of the private key associated with the node's address, and allows the node to accept the block. In addition, nodes will always consider the longest chain in the blockchain database (the "main chain") to be the correct one.
Global consensus is achieved, therefore, as soon as all nodes have accepted a block, and the block belongs to the main chain at every node.
Although many different configurations are possible, three specific options are available for configuring a GM-X blockchain's consensus protocol, depending on the business scenario that the blockchain supports:
Options 2 and 3 are configured using a combination of the mining diversity and mining turnover parameters.
The mining diversity parameter implements a constraint on the number of blocks which may be created by the same miner within a given window, where 0 ≤ mining diversity ≤ 1. The validity of a block is verified as follows:
This enforces a round robin schedule, in which the permitted miners must create blocks in rotation in order to generate a valid blockchain. The mining diversity parameter is a threshold which defines the strictness of the scheme. A value of 1 ensures that every permitted miner is included in the rotation, whereas a value of zero represents no restriction at all. In general, higher values are safer, but a value too close to 1 can cause the blockchain to freeze if some miners become inactive. For Option 3, a value of 0.75 is recommended as a reasonable compromise. To conserve resources, nodes will not attempt to mine on a chain in which they already mined one of the previous spacing-1 blocks.
As well as preventing abuse, mining diversity helps in the event the network splits temporarily into disconnected islands, perhaps due to a communications failure. This mishap will lead to a fork in the chain, as each island is unable to see the other's transactions and blocks. Once the network is reunited, the fork with the longer chain will be adopted as the global consensus. The diversity threshold ensures that the longer blockchain will belong to the island containing the majority of permitted miners, since the other island's chain will quickly freeze up.
The mining turnover parameter influences which of the eligible miners volunteers first to mine a new block, when more than one miner is eligible to do so. To illustrate, if miners is 20 and mining diversity is zero, then spacing is 1 and spacing-1 is zero so the block will always be accepted by the other nodes no matter who mines it. Therefore, the number of eligible miners will be 20. Alternatively, if miners is 20 and mining diversity is 0.75, then spacing is 15 so the block will be accepted only if its miner did not mine one of the previous spacing-1 (14) blocks. This reduces the number of eligible miners to 6 in the long run. The mining turnover parameter determines how long each of these eligible miners hesitates before volunteering. If mining turnover is 1 then each eligible miner chooses a random time delay (close to the target block time); so the miner hesitating the least, among the 20 or 6 eligible miners in these illustrations, will volunteer first. Alternatively, if mining turnover is zero then for both illustrations the miner who has not mined any of the previous 19 blocks will immediately volunteer without delay. Mining turnover values between zero and 1 will strike a balance between these behaviours.
Configuring a blockchain's consensus protocol is done by adjusting the <chain>/params.dat file as shown in Figure 2. This file can be found on the parent node in the blockchain data directory shown in Figure 1.
This initially contains the default values which were generated when the chain was created. If it is necessary to modify the default values, this must be done before the chain is started.Figure 2 - Update params.dat file
Parameter | Description | Default | Recommendation (Option 1) | Recommendation (Option 2) | Recommendation (Option 3) |
anyone-can-mine |
Apply no restriction to mining blocks for the chain, i.e. confirming transactions. Note that if this setting is true then proof-of-work mining will be enabled, and mining-diversity cannot be applied.
|
false |
default | false |
false |
mining-diversity |
Minimum proportion of permitted miners required to participate in round-robin mining to render a valid blockchain, between 0.0 (no constraint) and 1.0 (every permitted miner must participate). Unlike mining-turnover , this is a hard rule which determines whether a blockchain is valid or not. Note that if anyone-can-mine=true then mining-diversity cannot be applied.
|
0.3 |
default | 0.0 |
0.75 |
mining-turnover |
A value of 0.0 prefers pure round robin mining between an automatically-discovered subset of the permitted miners, with others stepping in only if a miner fails. In this case the number of active miners will be mining-diversity multiplied by the number of permitted miners, rounded up. A value of 1.0 prefers pure random mining between all permitted miners. Intermediate values set the balance between these two behaviours. Lower values reduce the number of forks, making the blockchain more efficient, but increase the level of mining concentration. Unlike mining-diversity , this is a recommendation rather than a consensus rule, and can be overridden by each node using the miningturnover runtime parameter. Overriding the mining-turnover parameter at a node is done by adjusting the miningturnover parameter in the node's <chain>/multichain.conf file in the blockchain data directory shown in Figure 1.
|
0.5 |
default | 0.0 |
1.0 |
After creating a blockchain and configuring its consensus protocol, start it by generating the genesis block using the command shown in Figure 3:
Figure 3 - Use command "multichaind <chain> -daemon" to create the genesis block
E:\Program Files\MultiChain>multichaind chain1 -daemon MultiChain 1.0.2 Daemon (latest protocol 10009) Looking for genesis block... Genesis block found Other nodes can connect to this node using: multichaind chain1@192.168.179.1:6311 This host has multiple IP addresses, so from some networks: multichaind chain1@192.168.98.1:6311 multichaind chain1@192.168.0.12:6311 Node started
Note here that the output shows both the IP address (192.168.179.1) and port (6311) used to communicate with this blockchain. Alternative IP addresses may also be available.
If you examine the contents of the params.dat file in the blockchain data directory (as shown in Figure 1) you will see two port numbers specified, as shown in Figure 4:
Figure 4 - Ports in params.dat file
default-network-port = 6311 # Default TCP/IP port for peer-to-peer connection with other nodes. default-rpc-port = 6310 # Default TCP/IP port for incoming JSON-RPC API requests.
The RPC port is used by the GM-X software to communicate with its local blockchain server.
The NETWORK port is used by the blockchain server to communicate with other servers (nodes) in the network. You may have to open this port in your firewall to allow access.
Once the daemon has been started it should be left running. If it is stopped it can be restarted using the command shown in Figure 5:
Figure 5 - Use command "multichaind <chain> -daemon" to start/restart the blockchain server
E:\Program Files\MultiChain>multichaind chain1 -daemon MultiChain 1.0.4 Daemon (latest protocol 10010) Chain chain1 already exists, adding 192.168.0.12:6311 to list of peers Other nodes can connect to this node using: multichaind chain1@192.168.0.12:6311 Listening for API requests on port 6310 (local only - see rpcallowip setting) Chain running protocol version 10009 Node ready.
Note here that the output shows both the network port (6311) and the RPC port (6310). These port numbers may be different for each blockchain.
The value for rpcallowip can be set in the local <chain>/multichain.conf file as described in MultiChain 1.0 runtime parameters.
If your installation is creating a new blockchain then jump back to Creating a new blockchain.
First, request to join the chain using the command shown in Figure 6 where <IP address> and <port> are obtained from the parent node.
Figure 6 - Use command "multichaind <chain>@<IP address>:<port>" to Request to join a blockchain
E:\Program Files\MultiChain>multichaind chain1@192.168.0.12:6311 MultiChain 1.0.2 Daemon (latest protocol 10009) Retrieving blockchain parameters from the seed node 192.168.0.12:6311 ... Blockchain successfully initialized. Please ask blockchain admin or user having activate permission to let you connect and/or transact: multichain-cli chain1 grant 1Mu1d47Q8aDKtUorS9di6oCi7cK7bsrG6DtPj5 connect multichain-cli chain1 grant 1Mu1d47Q8aDKtUorS9di6oCi7cK7bsrG6DtPj5 connect,send,receive
This will create a blockchain data directory similar to the one created in Figure 1.
Note that the output from this command specifies a 38 character string which is the address used for this node. This address must be communicated to the administrator of the parent node so that the join request can be granted.
On the parent node grant permission for the new node to join the chain using the command shown in Figure 7:
Figure 7 - Use command "multichain-cli <chain> grant <address> connect,send,receive" to grant access to a node's address
E:\Program Files\MultiChain>multichain-cli chain1 grant 1Mu1d47Q8aDKtUorS9di6oCi7cK7bsrG6DtPj5 connect,send,receive {"method":"grant","params":["1Mu1d47Q8aDKtUorS9di6oCi7cK7bsrG6DtPj5","connect,send,receive"],"id":1,"chain_name":"chain1"} e875f382d27574e0e610a08742370c7986bff2e704754e9b85aa2c7a8e48cb8c
The response from this command is the unique TXID (transaction Identity) which is generated by the blockchain server. Every operation will generate its own TXID.
Once permission has been granted you can use the command shown in Figure 5 to start the blockchain service. Should the server be stopped you can restart it using the same command.
It will be seen in Figure 6 and Figure 7 that the default method for joining a blockchain does not confer administrator or mining permissions to a new node when it joins the blockchain. However, consensus protocol configuration Option 2 and Option 3 require additional nodes to have mining permission.
This is done using the Update Blockchain Node Permissions screen. Based on the permissions shown in Figure 6 and Figure 7, this can only be done using the GM-X instance at the parent node, because changing permissions requires administrator permission which has not yet been granted to any of the other nodes.
Please refer to permissions consensus documentation should it become necessary for other nodes to have administrator permission.
In order to receive private messages each node must create a pair of private and public keys using the OpenSSL software mentioned in the Introduction and store them in a suitable directory. It may be a good idea to create a subdirectory in the data directory which was created when the chain was either created or joined, but you can use a directory of your choice. Note that this directory must be accessible by the GM-X application as the two files will be read by the application.
When you have created a subdirectory you must run the 3 commands shown in Figure 8 via the command line.
Figure 8 - Generate Private/Public key pair
set OPENSSL_CONF=E:\Program Files\OpenSSL-Win64\bin\openssl.cfg "E:\Program Files\OpenSSL-Win64\bin\openssl.exe" genpkey -algorithm RSA -out private_key.pem 2048 "E:\Program Files\OpenSSL-Win64\bin\openssl.exe" rsa -pubout -in private_key.pem -out public_key.pub
Note here that I am using the path E:\Program Files\OpenSSL-Win64\bin\ for the location of the OpenSSL software, but your path may be different. This command will create two files in the current directory:
The public key will later be loaded into the "pubkeys" stream so that it can be accessed by every other node in the network, but the private key should be kept entirely private and never communicated to anybody.
By default when the blockchain server receives a message it is simply added to its own database and nothing else. However, in order for the contents of a message to be processed by the GM-X application you must make a small modification to the <chain>/multichain.conf file as shown in Figure 9. This file can be found in the blockchain data directory shown in Figure 1. This initially contains the userid and password which were generated when the chain was created or joined, but can be amended to contain additional configuration parameters such as walletnotify.
Figure 9 - Update multichain.conf file
rpcuser=multichainrpc
rpcpassword=<random password>
walletnotify=php.exe F:/Apache2/HTDOCS/GMX-Transix/blockchain/blockchain_receive.php %m %s %n
Here the walletnotify option tells the blockchain server to run the specified program whenever a message is received. The example above runs the PHP executable on a script called blockchain_receive.php which is located in the blockchain directory of your GM-X installation. The following table shows all the options which are currently available for the walletnotify option.
Parameter | Description | Default |
walletnotify |
Execute this command when a transaction is first seen or confirmed, if it relates to an address in the wallet or a subscribed asset or stream. The substitutions below can be used in the command parameters to pass more information (only %s is supported if walletdbversion=1 ).
|
n/a |
The blockchain subsystem is used to send messages in a peer-to-peer network where each node in the network is another GM-X instance. Each of these nodes will also have an entry in the PARTY table of each instance in order to fully identify each node. When each of these parties joins the network its blockchain address must be added to the PARTY_CONTACT_MECHANISM table as shown below. If the party is a member of more than one blockchain then each blockchain should have an entry on the CONTACT_MECH_PURPOSE_TYPE table so that each address can be associated with the correct blockchain.
Party Contact Mechanism for Blockchain Address
This also makes use of an entry on the CONTACT_MECHANISM_TYPE table as shown below:
Contact Mechanism Type for Blockchain Address
Those tables that contain data which can be sent to different parties have been amended so that as well as requesting a party_id they will also request a contact_mech_id_blockchain which identifies the blockchain address for that party. Note that a party may be a member of more than one blockchain, and it will have a separate address for each blockchain. It is important that the right blockchain address is selected otherwise it will not receive the message.
This identifies all the blockchains that this GM-X instances uses to communicate with other nodes in the network. There may be more than one blockchain, and each chain will have its own set of STREAMS and NODES.
Field | Type | Description |
---|---|---|
chain_id | string | Identity string which is defined manually. |
chain_desc | string | Descriptive name. |
rpc_host | string | The IP address of the blockchain server. If it is on the same server as the GM-X application then use 127.0.0.1. |
rpc_port | number | The port number for API requests, as shown in Figure 5. |
cipher_method | string | The cipher method used to construct random passwords. This is fixed at aes-256-cbc at the moment, but may be changed in the future. |
public_key | string | The full path to the public_key.pub file created in Create Public/Private key pair. |
private_key | string | The full path to the private_key.pem file created in Create Public/Private key pair. |
parent_node | string | Optional. This points to an entry on the BLOCKCHAIN_NODE table. It is not relevant when this instance is the parent node in this network. |
start_date | date | Identifies when this entry became active. |
end_date | date | Optional. Identifies when this entry ceases to be active. Blank signifies an unspecified date in the future. |
This will list the contents of the BLOCKCHAIN_CHAIN table.
List Blockchain Chain
If you select an entry and press one of the navigation buttons it will activate another screen as follows:
New | This will active the Add Blockchain Chain screen. |
Update | This will active the Update Blockchain Chain screen. |
List Streams | This will active the List Blockchain Streams by Chain screen. |
List Nodes | This will active the List Blockchain Nodes by Chain screen. |
This will allow a new entry to be added.
Add Blockchain Chain
This will allow an existing entry to be updated.
Update Blockchain Chain
This identifies all the streams which exist in the various blockchain networks of which this GM-X instance is a member. Note that after a stream has been created a node will not automatically track the contents of that stream until it subscribes to that stream.
Field | Type | Description |
---|---|---|
chain_id | string | Links to an entry on the BLOCKCHAIN_CHAIN table. |
stream_id | string | Identity string which is defined manually. |
stream_ref | string | A reference number assigned by the blockchain server. For the root stream this will be 0-0-0. |
stream_desc | string | Descriptive name. |
create_txid | string | The identity of the transaction that created this stream. It is assigned by the blockchain server. |
is_open | boolean | Identifies whether this stream is OPEN or CLOSED. All subscribers to an OPEN stream have automatic read/write access. All subscribers to a CLOSED stream have automatic read access, but write access can be granted (or even revoked) in a separate operation. |
start_date | date | Identifies when this entry became active. |
end_date | date | Optional. Identifies when this entry ceases to be active. Blank signifies an unspecified date in the future. |
This will list all the streams which belong in the selected chain. Note that streams with the same name may exist in other chains. Initially it will be empty.
List Blockchain Streams by Chain
If you select an entry and press one of the navigation buttons it will activate another screen as follows:
Import | This will active the Import Blockchain Streams task. |
New | This will active the Add Blockchain Stream screen. |
Update | This will active the Update Blockchain Stream screen. |
Items | This will active the List Blockchain Stream Items screen. |
Update Permissions | This will active the Update Blockchain Stream Permissions screen. |
This task does not have a screen. It asks the blockchain server for a list of streams within the current chain then ensures that they exist in the database. This should be used to identify streams which were created by other nodes in the network.
This will allow the local node to create a new stream on the current blockchain. Note that details of streams created by other nodes will have to be imported.
Add Blockchain Stream
This will allow some details for a stream to be amended.
Update Blockchain Stream
This will allow the current node to change stream permissions either for itself or another node. Note that you can only change those permissions which your node has permission to change.
Update Blockchain Stream
From Address (the current node) may show more than one entry if additional addresses were created. This ability is not available through the GM-X interface as its use is not recommended. Each node should have only one address as anonymous addresses are only used in crypto-currencies to disguise the creator of a transaction.
Node Address will show all available nodes on the network from which one must be chosen. It is the permissions for this node that will be open for modification.
Is Subscribed can only be changed by the current node for the current node. In other words a node may only subscribe/unsubscribe itself.
If Is Open is 'Yes' then write access cannot be turned of.
This will list all the items (messages) in the selected blockchain stream. Note that this data is taken directly from the blockchain database as it does not exist in the GM-X database.
Note that the sort order is fixed at latest first as the blockchain database does not offer the same facilities as a relational database.
List Items by Blockchain Stream
If you select an entry and press one of the navigation buttons it will activate another screen as follows:
Read | This will active the Read Stream Item task. |
Read Decoded | This will active the Read Decoded Stream Item screen. |
This will show the message contents for the selected transaction(s).
If the message was sent as 'private' then only the raw encoded text will be shown, which will be unreadable. It will not be able to be decoded unless an entry exists on the ACCESS stream for this node address and this transaction id, in which case a "Decode Data" button will appear below the message. Press the button and the data will be decoded into readable text. Once this button has been pressed all subsequent private messages will automatically be decoded (if possible).
Read Stream Item
The line of File buttons will only appear if the XML document contains file data, in which case there will be a separate button for each where the file name will be shown in the button text. Click on a button to display its contents.
After pressing the "Decode data" button the data area will be converted into plain text similar to the following:
Item data decoded
When the blockchain data is being viewed by people such as auditors they will want to see the decoded data immediately without having to press another button, and they will want to see it in a structured manner instead of a single block of text. This screen will treat the XML document as a "tree" where each "branch" will initially be shown as a label with a "+" (plus sign) in front of it.
Read Decoded Stream Item
By clicking on this "+" sign the branch will be expanded to show its contents, as shown below, and the "+" sign will be converted to "-" (minus). Click on this and the branch will be collapsed.
Read Decoded Stream Item - branch expanded (1)
If the contents include another branch then this again will be shown as a label with a "+" sign.
Read Decoded Stream Item - branch expanded (2)
This identifies all the nodes who are members of this network. This includes the local GM-X instance as well as all remote instances. Each node will have its own blockchain address as well as an IP address.
Field | Type | Description |
---|---|---|
chain_id | string | Links to an entry on the BLOCKCHAIN_CHAIN table. |
node_address | string | Identity string which is assigned by the blockchain software. |
ip_address | string | The IP address and port used to communicate with this node on the network. If is_mine is true then it will be shown as ::1. |
is_mine | boolean | Indicates whether this entry is for this instance of GM-X or a remote instance. |
node_label | string | Optional. A user-friendly label for this node. |
party_id | number | Optional. Links to an entry on the PARTY table. |
perm_connect | boolean | Indicates whether this entry has CONNECT permission. |
perm_send | boolean | Indicates whether this entry has SEND permission. |
perm_receive | boolean | Indicates whether this entry has RECEIVE permission. |
perm_create | boolean | Indicates whether this entry has CREATE permission. |
perm_issue | boolean | Indicates whether this entry has ISSUE permission. |
perm_mine | boolean | Indicates whether this entry has MINE permission. |
perm_activate | boolean | Indicates whether this entry has ACTIVATE permission. |
perm_admin | boolean | Indicates whether this entry has ADMIN permission. |
start_date | date | Identifies when this entry became active. |
end_date | date | Optional. Identifies when this entry ceases to be active. Blank signifies an unspecified date in the future. |
This will list all the nodes which belong in the selected chain. Initially it will be empty.
List Blockchain Nodes by Chain
If you select an entry and press one of the navigation buttons it will activate another screen as follows:
New | This will active the Import Blockchain Nodes screen. |
Update | This will active the Update Blockchain Node screen. |
List Streams | This will active the Update Blockchain Node Permissions screen. |
This task does not have a screen. It asks the blockchain server for a list of nodes within the current chain then ensures that they exist in the database. This task can be run or rerun at will.
This will allow the following details to be updated after the nodes have been imported:
Update Blockchain Node
This will allow the current node to change node permissions either for itself or another node. Each permission is shown as a checkbox which can be toggled ON or OFF. Note that you can only change those permissions which your node has permission to change.
Update Blockchain Node Permissions
In order for data to be extracted from the current GM-X application and sent over the blockchain network to other nodes the application has to fire one of these blockchain triggers. Each trigger identifies a set of circumstances - an insert/update/delete operation on a particular database table - which must be met in order for that trigger to be fired. This monitoring is performed automatically by the framework as it knows both the name of the table and the operation which is being performed. No changes need to be made to any application component in order to configure any triggers. When the operation is successfully committed a new blockchain message will be constructed and sent out (published).
Note that the execution of an online task cannot fire more than one trigger, so the following situations will result in excess triggers being ignored:
The configuring of blockchain triggers is only required when sending messages from the current GM-X instance. No configuration of incoming messages is required as every message will be processed based on what it contains.
Field | Type | Description |
---|---|---|
trigger_id | number | A unique identity number which is supplied by the system. |
subsys_dir | string | The subsystem directory which contains table_id. |
table_id | string | The name of the table. |
table_id_alias | string | Optional. in some situations the table has an alias. For example, the ORDER_HEADER table has several variants:
|
chain_id | string | Links to an entry on the BLOCKCHAIN_CHAIN table. This identifies the chain to which the message will be sent. |
stream_id | string | Links to an entry on the BLOCKCHAIN_STREAM table. This identifies the stream to which the message will be sent. |
start_date | date | Identifies when this entry became active. |
end_date | date | Optional. Identifies when this entry ceases to be active. Blank signifies an unspecified date in the future. |
trigger_column | string | Optional. Identifies the column which contains the trigger_value. |
trigger_value | string | Optional. Identifies the value in the trigger_column which will cause the trigger to be fired. |
distribution_type | string | Identifies the recipients of the message. Options are:
|
distribution_table | string | Optional. Identifies the table which contains one or more blockchain address to which the message should be sent. |
Note here that trigger_column and trigger_value must be either both empty or both non-empty.
Distribution_table must be empty unless distribution_type is set to 'database table', in which case it must satisfy the following conditions:
This will list entries on the BLOCKCHAIN_TRIGGER table. The start_date and end_date columns can be used to make entries become active or inactive on specified dates.
List Blockchain Trigger
If you select an entry and press one of the navigation buttons it will activate another screen as follows:
New | This will active the Add Blockchain Trigger screen. |
Update | This will active the Update Blockchain Trigger screen. |
Related Tables | This will active the Tree Structure for Related Tables screen. |
This will allow a new entry to be added to the BLOCKCHAIN_TRIGGER table.
Add Blockchain Trigger
Note that certain dropdown lists will be empty until a previous value has been selected:
This will allow some of the details for a Blockchain Trigger to be amended.
Update Blockchain Trigger
By default when a blockchain trigger is fired only the data from table_id on the BLOCKCHAIN_TRIGGER table will be included in the message. This may not be enough as the data for an object or event may be spread across several tables, so the identity of each related table can be specified here so that data from that table can be included in the outgoing message.
In this section the table_id on the associated BLOCKCHAIN_TRIGGER table is known as the root table or level 0 (zero) in the tree structure. The entries at level 1 (one) are related to the root table entry at level 0. Each entry at level 2 is related to an entry at level 1, and so on. There is no limit to the number of levels, nor is there any limit to the number of entries at each level. The only validation rule is that the table at level X+1 must actually have a relationship in the data dictionary to its senior table at level X.
Each node in this tree structure can have only one senior/superior, but any number of juniors/subordinates. The same table_id can appear in several places in the same tree structure as its place in the tree is controlled by its node_id.
Field | Type | Description |
---|---|---|
trigger_id | number | Links to an entry on the BLOCKCHAIN_TRIGGER table. |
node_id | number | A unique identity number which is supplied by the system. |
subsys_dir | string | The subsystem directory which contains table_id. |
table_id | string | The name of the table. |
table_id_alias | string | Optional. in some situations the table has an alias. For example, the ORDER_HEADER table has several variants:
|
node_id_snr | number | Optional. Links to an entry on RELATED_TABLE table which indicates the senior (parent) table to this entry. An empty value indicates that the senior table is the root table, the one on the associated BLOCKCHAIN_TRIGGER table. |
parent_or_child | string | Indicates if this table is the parent or child of the senior table. In a relational database two tables can be linked in a one-to-many relationship where the "one" is also known as the senior, parent or superior, and the "many" is also known as the junior, child, or subordinate. |
The details from parent tables may be needed for referential integrity. For example, in an RFQ a REQUEST_ITEM contains a column called product_id which is a foreign key pointing to an entry on the PRODUCT table. In this case the product_id on its own would be useless without the associated product data. Note that each of these parent tables may also have parents of their own which should also be included in the blockchain message.
This screen shows the root table from the associated BLOCKCHAIN_TRIGGER table at the top, with the related tables underneath. These related tables are shown in a tree structure which consists of various levels. The first set of entries is at level 1 which means that each is related to the root table at level 0. If an entry has a in front of it it means that it has related tables of its own at the next level down.
Tree Structure for Related Tables
If you press one of the navigation buttons it will activate another screen as follows:
Add Level 1 Relations | This will active the Add Level 1 Relations task. |
Add Level 1 Table | This will active the Add Level 1 Table screen. |
The following buttons require a subordinate entry to be selected first | |
Add Subordinate Relations | This will active the Add Subordinate Relations task. |
Add Subordinate Table | This will active the Add Subordinate Table screen. |
Each line shows table data in the format: "<subsys_dir>.<table_id> (<table_alias>) [Parent|Child]" where "[Parent|Child]" indicates how this table is related to the table at the previous level.
If you click on a two things will happen:
If you click on a the results will be reversed.
The following diagram shows the same structure with all branches expanded.
Tree Structure for Related Tables (expanded)
This task does not have a screen. It will allow multiple entries to be added to the RELATED_TABLE table where node_id_snr is blank, which means that table_id_snr will be taken from the BLOCKCHAIN_TRIGGER table.
It will obtain the details of all those tables which are related to table_id_snr, both as parents and as children, and will then add a new entry to the RELATED_TABLE table for each of these tables.
This will allow a single entry to be added to the RELATED_TABLE table where node_id_snr is blank, which means that table_id_snr will be taken from the BLOCKCHAIN_TRIGGER table.
Add Level 1 Table
You must first select whether you want to add a parent or child table, add this will cause the dropdown list for table_id to be populated with the qualifying entries. These entries will be in the format: "<table_id_alias|table_id> [<subsys_dir>]".
This task does not have a screen. It is identical to Add Level 1 Relations except that node_id_snr will be non-blank as it indicates a subordinate entry which was selected on the previous screen (Tree Structure for Related Tables).
This is identical to Add Level 1 Table except that node_id_snr is non-blank as table_id_snr comes from the RELATED_TABLE table.
Add Level 1 Table
The purpose of this subsystem is to take certain data from one GM-X instance and send it to other nodes on the blockchain network so that they have copies of exactly the same data. Each GM-X instance has its own copy of the BLOCKCHAIN_TRIGGER table which identifies what data needs to be sent out from that instance. Different instances can send different data. For example, a Buyer may send a Request for Quotation (RFQ) to a number of Sellers/Suppliers, and each Seller/Supplier will respond by sending a Quotation back to the Buyer. Notice here that the Buyer will send RFQs but not Quotations, and each Seller will send Quotations but not RFQs.
Data is only sent out from a GM-X instance when a change is made to the GM-X database as a result of an INSERT, UPDATE or DELETE operation on one of its database tables. Each of these operations can only work on one table at a time, and as each operation is handled by the same piece of code in the framework this code has been modified to perform a lookup on the BLOCKCHAIN_TRIGGER table to see if that operation on that table will require a blockchain message to be sent. There are three possibilities:
The latter option is for those circumstances where an object such as an RFQ or Quotation has data which spans several database tables such as a HEADER and several LINE_ITEMS, and where that data is built up over several separate operations. In this situation the HEADER table will contain a status field which starts off as 'Pending', and when all the LINE_ITEMS have been assembled the status is changed to something else, such as 'Sent to Supplier'. In this situation the data is not eligible to be sent out until the status is changed.
If the correct trigger conditions are met the framework will first store the details in memory, and only send the message out if the transaction ends successfully with a COMMIT operation. If there is an error then the COMMIT will be replaced with a ROLLBACK, any database changes made during that transaction will be undone, and the blockchain message will not be sent. The data stored in memory is as follows:
Immediately after the COMMIT operation these values will be sent to a separate PHP script which will run in the background so as not to delay the current online task.
This operation is handled by script blockchain_send.php which will be run as a command line task in the background. When it is activated it will be passed the three arguments identified above - trigger_id, table_id and primary_key. If the operation was an INSERT or UPDATE it will use these values to instantiate the object associated with that table_id and use that object to read the record identified in primary_key. After reading the specified record it will begin to construct an XML document in a format similar to the following:
<?xml version="1.0" encoding="UTF-8"?> <update_vehicle> <vehicle_id>20202000000000000000000000000002</vehicle_id> <vehicle_type_id>AC</vehicle_type_id> <vehicle_reg_no>FOO1</vehicle_reg_no> <global_asset_id>bbb (March 12 @ 18:17)</global_asset_id> <created_date>2017-12-25 10:30:41</created_date> <created_user>AJM</created_user> <revised_date>2018-03-12 18:17:22</revised_date> <revised_user>AJM</revised_user> </update_vehicle>
The first line is the standard XML declaration. The second line is a combination of the operation name and the table name. The remaining lines identify the values for each of the columns within that table. Note that these are all the columns which exist in that table and not just those columns which were affected during this operation.
If the trigger has any associated records on the RELATED_TABLE table then these will be processed in turn and data from the related records will be added into the XML document after the last column for that table. These will be grouped together in two separate elements, one for parent tables and another for child tables. If any of these elements has no data it will not be included. Within each of these elements there will be a separate sub-element for each table. In the above example the VEHICLE table has a foreign key which links to an entry on the VEHICLE_TYPE table, so the full XML document will be as follows:
<?xml version="1.0" encoding="UTF-8"?> <update_vehicle> <vehicle_id>20202000000000000000000000000002</vehicle_id> <vehicle_type_id>AC</vehicle_type_id> <vehicle_reg_no>FOO1</vehicle_reg_no> <global_asset_id>bbb (March 12 @ 18:17)</global_asset_id> <created_date>2017-12-25 10:30:41</created_date> <created_user>AJM</created_user> <revised_date>2018-03-12 18:17:22</revised_date> <revised_user>AJM</revised_user> <parent_tables> <vehicle_type> <vehicle_type_id>AC</vehicle_type_id> <vehicle_type_desc>Armoured Car</vehicle_type_desc> <created_date>2017-12-25 10:30:40</created_date> <created_user>AJM</created_user> <revised_date/> <revised_user/> </vehicle_type> </parent_tables> </update_vehicle>
Each record in the RELATED_TABLE table may have subordinate records of its own, so each record in the parent_tables or child_tables area may have parents and children of its own, and so on and so on in a fully recursive manner.
If a record references a disk file, identified by calling the getFileBody() method, then this will also be included in the XML document in an element called rdc_file_body which will have two sub-elements called file_name and base64_encoded. The latter will contain the file contents in encoded form as binary data cannot be safely transported through layers that are not 8-bit clean. It will look something like the following:
<revised_user>AJM</revised_user> <rdc_file_body> <file_name>foobar.pdf</file_name> <base64_encoded>JVBERi0xLjQKJeLjz9MKJVBERi0xLjQKJeLjz9MKJVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9U eXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL01lZGlhQm94IFswIDAgNTk1LjI4MCA4NDEuODkwXQov VHJpbUJveCBbMC4wMDAgMC4wMDAgNTk1LjI4MCA4NDEuODkwXQovUmVzb3VyY2VzIDIgMCBSCi9H cm91cCA8PCAvVHlwZSAvR3JvdXAgL1MgL1RyYW5zcGFyZW5jeSAvQ1MgL0RldmljZVJHQiA+PiAK L0NvbnRlbnRzIDQgMCBSPj4KZW5kb2JqCjQgMCBvYmoKPDwvRmlsdGVyIC9GbGF0ZURlY29kZSAv ..... </base64_encoded> </rdc_file_body> </alert_detail>
If the operation was a DELETE the XML document will only contain those columns which are part of the primary key as all non-key columns are irrelevant in that operation. The data for any parent or child tables will also be irrelevant as the cascade deletion of any child records at the remote node will have already been defined in the table structure file which was exported from the Data Dictionary.
It is a feature of a blockchain that every message sent out will automatically be copied to the blockchain database which is maintained at every node in the network. This means that every node can potentially read every message, which is not good when a message was designed to be read only by authorised recipients. For example, when a Seller/Supplier sends a quotation back to the Buyer he does not want that information read by anybody other than the Buyer. This situation is handled by making use of the PUBKEYS and ACCESS streams as follows:
After a node sends a message, it is broadcast to all the nodes in the network, and is added to a transaction pool at each node.
One of the permitted miners will batch this and other messages into a block, and sign the block as explained above in Process of Creating New Blocks. The miner which performs this job is determined according to the blockchain's consensus protocol configuration.
The first miner to complete the verification process for a block will broadcast the block to all the other nodes, which in turn will verify the block and determine if it belongs to the main chain as explained above in Process of Accepting Newly-Created Blocks.
It will only be possible for the GM-X instance at each node to receive a message after the block to which it belongs has been confirmed by the Blockchain Server at the node, meaning that:
This operation is handled by script blockchain_receive.php which will be run as a command line task in the background provided that the relevant details have been added to the multichain.conf file. When activated it will receive the following arguments: chain_id, txid and block_height. It will then perform the following steps:
This will then provide an XML document which will be processed as follows:
Note that the processing of entries in the parent_tables and child_tables elements is recursive as each entry can have its own set of parent_tables and child_tables elements. Each entry identifies a table in the database, so it is easy to instantiate an object for that table and have that object process the data.
Note also that the processing of a received message does not require any configuration on the BLOCKCHAIN_TRIGGER or RELATED_TABLE tables as the entire contents of the XML document.
Many GM-X tables have auto-incrementing primary keys (also known as "technical keys" or "surrogate keys") causing the underlying relational database management system (RDBMS) or GM-X application programs to issue new values by adding 1 to the greatest existing primary key value when inserting new records into these tables. Whenever data from these tables is sent to the blockchain network, these values must be globally unique to prevent collisions when messages are received at the other nodes. But there can be no guarantee of global uniqueness when multiple GM-X instances are issuing numeric identification keys independently from one another.
To solve this problem, most GM-X auto-incrementing primary keys contain a maximum of 38 numeric digits divided into 2 implicit segments. The most significant segment, which may contain anywhere from 1 from 12 significant digits, is reserved for a globally unique participant identifier (the "Participant ID"); and the least significant segment contains auto-incrementing values that are left-padded with zeroes, if necessary, to form a fixed precision of 26 digits. Whenever a GM-X instance issues a new key value, it auto-increments the least significant segment by 1 and then prepends the Participant ID associated with that GM-X instance. This strategy completely avoids data collisions when messages are received at other GM-X instances by guaranteeing that all key values sent to a blockchain are globally unique.
A globally unique Participant ID is assigned to each GM-X instance ahead of time, and cannot be changed. It may represent one of the following:
No two GM-X instances on a particular blockchain can have the same Participant ID. However, because each GM-X instance can join more than one blockchain, it will use the same Participant ID for each of the blockchains it joins.
Generally speaking no application component should need to be amended in order to be included in the transfer of data over a blockchain, but there are some exceptions which are identified below. These are customisable methods which need only be copied into a table class and filled with code should it be necessary.
If a database record contains a reference to a binary file, such as an image, the contents of this file may be held either in the database itself or in the file system. This method should therefore be modified to return two values:
This will allow data to be adjusted before it is sent out to the blockchain. In cases where a record contains financial information in two different currencies, such as the transaction currency and the sender's home/functional currency, then all values in the sender's home currency should be nullified before being sent.
This is the reverse of _cm_getFileBody. It will return the contents of filebody so that it can be stored in the correct place.
This is the reverse of _cm_blockchain_send. In cases where a record contains financial values in two currencies - transaction currency and home/functional currency - only the values for the transaction currency will be supplied. If the receiver's home/functional currency is different then this method should be used to lookup the exchange rate and put it into the record's exchange_rate field. This will then be used to convert all the amounts in the transaction currency to the receiver's home/functional currency.
Date created: 9th March 2018
Copyright © 1999-2020 by Geoprise Technologies Licensing, All Rights Reserved.