Deploying A Smart Contract To The Open Application Network

Follow

Deploying a smart contract to the Open Application Network

The Open Application Network Java API

Assuming that the smart contract is stored in a .sol on the filesystem, the user must take the following steps for deploying a smart contract on the Open Application Network:

  1. Connect to the Open Application Network Java API.
  2. Unlock the account being used for sending the contract creation transaction.
  3. Load the solidity contract from the filesystem into a variable.
  4. Compile the contract.
  5. Send the contract creation transaction to the Open Application Network.
  6. Wait for the contract creation transaction to be “mined” or included in at least 1 block.

The following is a Java program that uses the Open Application Network Java API to execute these steps:

IAionAPI api = IAionAPI.inst();
ApiMsg apiMsg = new ApiMsg();
apiMsg.set (api.connect("tcp://127.0.0.1:8547"));
if (apiMsg.error()) {
    System.out.println("Aion api connection could not be established.");
    closeApi();
    // safely close API connection
}

// set up the arguments for unlock account operation
Address account = Address.wrap("cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe");
String password = "password";
int unlockTimeout = 300; 
	
// unlock an account
apiMsg.set(api.getWallet().unlockAccount(account, password, unlockTimeout));
if (apiMsg.error() || !(boolean)apiMsg.getObject()) {
	System.out.println("Unlock account failed! Please check your password  " + apiMsg.getErrString());
	// cleanup() on return
} 
	 
// get the Smart Contract code from file
String sc = null; 
try {
	sc = new String(Files.readAllBytes(Paths.get("/path/to/Ticker.sol")));
} catch (IOException e) {
	e.printStackTrace();
	closeApi();
	// safely close API connection
}
// contract creation:
// this function blocks until the contract creation transaction
// has been included in at least one block on the Blockchain
long energyLimit = 1_000_000L;
long energyPrice = 1L;
apiMsg.set(api.getContractController().createFromSource(sc, account, energyLimit, energyPrice));
if (apiMsg.error()) {
	System.out.println("Deploy contract failed with error: " + apiMsg.getErrString());
	closeApi();
	// safely close API connection
} 

IContract contract = api.getContractController().getContract();

// make sure to save the ABI definition for the contract since an API
// limitation is that in order to create a Contract object, one needs the
// contract address and the ABI definition
String contractAddress = contract.getContractAddress();
String contractAbi = contract.getAbiDefToString();
	
closeApi(): {
		if (api != null)
			api.destroyApi();

 

A Sample __Hello World__ greeter smart contract

Your first citizen: the Greeter

The Greeter is an intelligent digital entity that lives on the blockchain and is able to have conversations with anyone who interacts with it, based on its input.

Here is its code:

contract Mortal {
    /* Define variable owner of the type address */
    address owner;

    /* This function is executed at initialization and sets the owner of the contract */
    function Mortal() { owner = msg.sender; }

    /* Function to recover the funds on the contract */
    function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

contract Greeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;

    /* This runs when the contract is executed */
    function Greeter(string _greeting) public {
        greeting = _greeting;
    }

    /* Main function */
    function greet() constant returns (string) {
        return greeting;
    }
}

You'll notice that there are two different contracts in this code: "mortal" and "greeter". This is because Solidity (the high level contract language we are using) has inheritance, meaning that one contract can inherit characteristics of another. This is very useful to simplify coding as common traits of contracts don't need to be rewritten every time, and all contracts can be written in smaller, more readable chunks. So by just declaring that greeter is mortal you inherited all characteristics from the "mortal" contract and kept the greeter code simple and easy to read.

The inherited characteristic "mortal" simply means that the greeter contract can be killed by its owner, to clean up the blockchain and recover funds locked into it when the contract is no longer needed. Contracts in ethereum are, by default, immortal and have no owner, meaning that once deployed the author has no special privileges anymore. Consider this before deploying.

USING REMIX

As of 2018, the most convenient way to develop contracts is using Remix, an online IDE.

To access the compiled code, ensure that the dropdown menu on the right pane has greeter selected. Then click on the Details button directly to the right of the dropdown. In the popup, scroll down and copy all the code in the WEB3DEPLOY textbox.

Create a temporary text file on your computer and paste that code. Make sure to change the first line to look like the following:

var _greeting = "Hello World!"

Now you can paste the resulting text on your geth window, or import the file with loadScript("yourFilename.js"). Wait up to thirty seconds and you'll see a message like this:

Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e

You may have to "unlock" the account that is sending the transaction using the password you picked in the beginning because you need to pay for the gas costs to deploying your contract: 

Within less than a minute, you should have a log with the contract address, this means you've successfully deployed your contract. You can verify the deployed code (which will be compiled) by using this command:

eth.getCode(greeter.address)

If it returns anything other than "0x" then congratulations! Your little Greeter is live! If the contract is created again (by performing another eth.sendTransaction), it will be published to a new address.

Run the Greeter

In order to call your bot, just type the following command in your terminal:

greeter.greet();

Since this call changes nothing on the blockchain, it returns instantly and without any gas cost. You should see it return your greeting:

'Hello World!'

 

 

More resources...

Interacting with the Smart Contract

There are three types of interactions one can have with Smart Contracts using the Aion Java API:

  1. Contract Creation Transactions This is the transaction which creates the smart contract on the Aion network; this translates to the fact that for any fully-validating node on the network which has a block on its consensus chain that includes this contract creation transaction, then that block has the ability to respond to any contract calls or transactions. The use of this type of transaction with the Aion Java API has been covered in the previous section.

  2. Contract Calls These are reads from the Contract storage of the API-connected node; since these are simple database reads and do not involve any state changes for contract storage and therefore does not involve the consensus process; this information can be retrieved directly from the contract storage database for the smart contract.

  3. Contract Transactions These are state changes to the contract storage and require a consensus process to guarantee that the contract state change is agreed to and is propagated across a majority of nodes on the network.

All interaction with smart contracts happens using the Contract object using the IContract interface. The IContract interface has no public constructors.

Please see The Open Application Network java API documentation for all available overloads.

The Contract object represents a smart contract deployed on-chain. There are two methods of obtaining and using a Contract instance:

  1. At the contract-deploy time, the contract instance returned can be used for sending transactions to that contract. After The Open Application Network API connection has been closed or this reference is lost, a new Contract instance must be created pointing to the same Smart Contract

  2. In order to create a new Contract instance, the address of the contract and the ABI definition is required (this is both a limitation and feature, since this allows the Open Application Network Java API to do compile-time checks, allowing programmers to write correct programs without requiring them to test transaction calls against a test Blockchain, just to validate if the transaction, as described in software does not have any errors in its declaration, as is the case in Web3)

The Contract object uses the currying pattern to prepare the Contract for a transaction, by changing its state and returning the object. Calling the .execute() function will send the contract transaction or contract call to the Kernel.

The following example shows how to interact with the Ticker contract:

  1. Assuming that an active connection to the Open Application Network Java API exists, and the known account whose address is stored in the variable String account has been unlocked.
  2. A contract object is created from the known contract address and ABI for the Tickercontract, which we acquired in the last code snippet.
  3. A contract transaction is sent, calling the tick() function.
  4. The contract state change is verified by using the contract call showMeCount()
// open a connection to the Open Application Network API called api
// ...

// unlock account to be used for transactions
// ...

ApiMsg apiMsg = new ApiMsg();
String abiDef = "known ABI definition";
Address contractAddress = Address.wrap("known contract address");

// create a contract object from a known smart contract address
apiMsg.set(api.getContractController().getContractAt(account, contractAddress, abiDef));
    
if (apiMsg.error()) {
	System.out.println("Contract instantiation failed!" + apiMsg.getErrString());
	closeApi();
	// safely close API connection
}

IContract contract = api.getContractController().getContract();
// perform a contract transaction by calling the tick() function:
// by default, the execute() function blocks until this
// transaction has been included in at least one block on the Blockchain
apiMsg.set(contract.newFunction("tick")
      .build()
      .execute());

if (apiMsg.error()) {
	System.out.println("Function execution error! " + apiMsg.getErrString());
	closeApi();
	// safely close API connection
}
	
apiMsg.set(contract.newFunction("showMeCount")
.build()
.execute());
	
if (apiMsg.error()) {
	System.out.println("Function showMeCount error! " + apiMsg.getErrString());
	closeApi();
	// safely close API connection
}

int tickCount = (int) apiMsg.getObject();

// now you can verify that the value of the count variable
// in the Ticker contract has incremented by printing out this value to std.out
System.out.println("Ticker contract count value: " + tickCount);

// more operations
// ...
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.