In-depth talk about Ethereum smart contracts

This article is excerpted from the book "Blockchain Development Guide"
block chain direction submission, article error correction, for reports, please email [email protected]

What is a contract?

A contract is a collection of code (its function) and data (its state) that exists at a specific address on the Ethereum blockchain. Contract accounts can pass information between each other and perform Turing-complete operations. Contracts run on the blockchain on what is known as the Ethereum Virtual Machine (EVM) bytecode (a binary format specific to Ethereum).

Contracts are typically written in a high-level language such as Solidity and then compiled into byte code uploaded to the blockchain.

There are also other languages ​​that can be used to write smart contracts such as Serpent and LLL, which are further explained in the next section. Decentralized Application Development Resources lists comprehensive development environments, developer tools to help you develop in these languages, and features such as testing and deployment support.

Ethereum High Level Language

Contracts run on the blockchain on what is known as the Ethereum Virtual Machine (EVM) bytecode (a binary format specific to Ethereum). However, contracts are typically written in high-level languages ​​such as Solidity, which are compiled into bytecodes uploaded to the blockchain using the Ethereum Virtual Machine compiler.

Below are the high-level languages ​​that developers can use to write smart contracts for Ethereum.

  1. Solidity
    Solidity is a JavaScript-like language that you can use to develop contracts and compile to Ethereum Virtual Machine bytecode. It is currently the most popular language for Ethereum.
  2. Serpent
    Serpent is a Python-like language that can be used to develop contracts compiled into Ethereum Virtual Machine byte code. It strives for simplicity, combining the efficiency benefits of low-level languages ​​with the ease of use of programming styles, while contract programming adds unique domain-specific capabilities. Serpent is compiled with LLL.
  3. LLL
    Lisp Like Language (LLL) is a low-level language similar to Assembly. It strives for simplicity; essentially just a little wrapper around the Ethereum Virtual Machine.
  4. Mutan (deprecated)
    Mutan is a statically typed, C-like language developed and designed by Jeffrey Wilcke. It is no longer maintained.

write contract

No language is complete without the Hello World program. Solidity operates within the Ethereum environment, and there is no obvious way to "output" strings. The closest we can do is to use logging events to put strings into the blockchain, example:

contract HelloWorld {
event Print(string out);
function() { Print("Hello, World!"); }
}

Every time it executes, the contract creates a log entry in the blockchain with the "Hello, World!" parameter printed.
See also: Solidity docs for more examples and guidance on writing Solidity code.

Compile the contract

Compilation of solidity contracts can be done through a number of mechanisms.

  • This is achieved through the command line using the solc compiler.
  • Use web3.eth.compile.solidity (this still requires the solc compiler to be installed) in the javascript console provided by geth or eth.
  • Implemented via the online Solidity real-time compiler.
  • Implemented through the Meteor dapp Cosmo, which builds solidity contracts.
  • Implemented through the Mix IDE.
  • Implemented through the Ethereum wallet.

Note: More information on solc and compiling Solidity contract code can be found here.

1. Set up the solidity compiler in geth

If you start the geth node, you can see which compilers are available. An example is as follows:

\> web3.eth.getCompilers();
["lll", "solidity", "serpent"]

This directive returns a string showing which compiler is currently available.
Note: the solc compiler is installed with cpp-ethereum. Alternatively, you can create your own.
If your solc executable is not in the standard location, you can specify a custom route for the solc executable with the --solc flag. An example is as follows:

$ geth --solc /usr/local/bin/solc

Or you can set this option during execution via the console:

\> admin.setSolc("/usr/local/bin/solc")
solc, the solidity compiler commandline interface
Version: 0.2.2-02bb315d/.-Darwin/appleclang/JIT linked to libethereum-1.2.0-8007cef0/.-Darwin/appleclang/JIT
path: /usr/local/bin/solc

2. Compile a simple contract

Let's compile a simple contract source, the example is as follows:

source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"

This contract provides a single method multiply, which is called with a positive integer a and returns a*7.

Now prepare to compile solidity code with eth.compile.solidity() in the geth JS console:

\> contract = eth.compile.solidity(source).test
{
code: '605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056',
info: {
language: 'Solidity',
languageVersion: '0',
compilerVersion: '0.9.13',
abiDefinition: [{
constant: false,
inputs: [{
name: 'a',
type: 'uint256'
} ],
name: 'multiply',
outputs: [{
name: 'd',
type: 'uint256'
} ],
type: 'function'
} ],
userDoc: {
methods: {
}
},
developerDoc: {
methods: {
}
},
source: 'contract test { function multiply(uint a) returns(uint d) { return a
*
7; } }'
}
}

Note: The compiler is available via RPC and therefore via web3.js, to any Ðapp in the browser that connects to geth via RPC/IPC.

The following example will show you how to use the compiler with geth via JSON-RPC.

\$ geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain ' * ' --mine console 2>> ~/eth/eth.log
$ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test {

Single-source compiler output will give you contract objects, each representing a separate contract. The actual return value of eth.compile.solidity is a mapping of contract names to contract objects. Since the contract name is test, eth.compile.solidity(source).test will give a test contract pair containing the following fields:

  • Code: Compiled Ethereum Virtual Machine byte code.
  • Info: Extra metadata output from the compiler.
  • Source: source code.
  • Language: Contract language (Solidity, Serpent, LLL).
  • LanguageVersion: The contract language version.
  • compilerVersion: The solidity compiler version used to compile this contract.
  • abiDefinition: The binary interface definition of the application.
  • userDoc: User's NatSpec Doc.
  • developerDoc: The developer's NatSpec Doc.

The immediate structuring of the compiler output (to code and info) reflects two very different deployment paths. The compiled Ethereum virtual machine code and a contract creation transaction are sent to the block, the rest (info) will ideally live on the decentralized cloud, and the publicly verified metadata executes the code on the blockchain .

If your source contains multiple contracts, the output will include one entry per contract, and the corresponding contract info object can be retrieved using the contract name as the property name. You can try it by detecting the current GlobalRegistrar code:

contracts = eth.compile.solidity(globalRegistrarSrc)

Create and deploy contracts

Before you start reading this section, make sure you have an unlocked account and some funds.

Now create a contract on the blockchain by sending a transaction to an empty address using the Ethereum Virtual Machine code from the previous chapter as data. An example is as follows:

Note: This is easier to do with the online Solidity real-time compiler or the Mix IDE program.

var primaryAddress = eth.accounts[0]
var abi = [{ constant: false, inputs: [{ name: 'a', type: 'uint256' } ]
var MyContract = eth.contract(abi)
var contract = MyContract.new(arg1, arg2, ..., {from: primaryAddress, data: evmByteCodeFromPrevio

All binary data is serialized in hexadecimal format. Hex strings will always have a hex prefix of 0x.

Note: Note that arg1, arg2, ... are contract constructor parameters in case it is to accept parameters. If the contract does not require constructor parameters, these parameters can be ignored.

It's worth pointing out that this step requires you to pay to perform it. Once the transaction successfully enters the block, your account balance (which you put in the from field as the sender) will be deducted according to the gas rules of the Ethereum virtual machine. After some time, your transaction will appear in a block, confirming that the state it brings is consensus. Your contract now lives on the blockchain.

Doing the same thing asynchronously looks like this:

MyContract.new([arg1, arg2, ...,]{from: primaryAccount, data: evmCode}, function(err, contract) {
if (!err && contract.address)
console.log(contract.address);
});

Interact with contracts

Interacting with contracts is typically done with an abstraction layer such as the eth.contract() function, which returns a javascript object, along with all available contract functions, as callable javascript functions.

The standard way to describe the functionality available to a contract is an ABI definition. This object is a string that describes the call signature and return value for each available contract function. An example is as follows:

var Multiply7 = eth.contract(contract.info.abiDefinition);
var myMultiply7 = Multiply7.at(address);

All function calls specified in the ABI are now available in the contract instance. You can call methods on these contract instances in one of two ways.

\> myMultiply7.multiply.sendTransaction(3, {from: address})
"0x12345"
> myMultiply7.multiply.call(3)
21

When called with sendTransaction, the function call is performed by sending the transaction. It costs Ether to send, and the call is permanently recorded on the blockchain. The return value of a call made in this way is the transaction hash table.

When called with call, the function is executed locally in the Ethereum virtual machine, and the function return value is returned with the function. Calls made in this way are not recorded on the blockchain and therefore do not change the internal state of the contract. This way of calling is called constant function call. Calls made in this way do not cost ether.

If you are only interested in the return value, then you should use call. If you only care about side effects of contract state, you should use sendTransaction.

In the above example, there are no side effects, so sendTransaction will just burn gas, increasing the entropy of the universe.

contract metadata

In the previous chapters, it was revealed how to create contracts on the blockchain. Now for the rest of the compiler output, contract metadata or contract information.

When interacting with contracts that you didn't create, you may want to document or view the source code. Contract authors are encouraged to provide such visible information, which they can register on the blockchain or through third-party services such as EtherChain. The Admin API provides a convenience method for all contracts that choose to register to obtain this bundle. An example is as follows:

// get the contract info for contract address to do manual verification
var info = admin.getContractInfo(address) // lookup, fetch, decode
var source = info.source;
var abiDef = info.abiDefinition

The underlying mechanisms for this work are:

  • Contract information is uploaded to an identifiable place with a publicly accessible URI.
  • Anyone can find out what URI is just by knowing the contract address.

These requirements can be achieved with just 2 steps of blockchain registration. The first step is to register the contract code (hash table) with the content hash table in a contract called HashReg. The second step is to register a url with the content hash table in the UrlHint contract. These registry contracts are part of the Frontier release and are already involved in Homestead.

To know the contract address to query the url and get the actual contract metadata package, it is enough to use this mechanism.

If you are a conscientious contract creator, please follow these steps:

  1. Deploy the contract itself to the blockchain
  2. Get contract information json file
  3. Deploy the contract information json file to any url of your choice
  4. Registration code scatter table -> content scatter table -> url

The JS API makes this process very easy by providing helpers. Call admin.register to extract information from the contract, write the json sequence in the specified file, calculate the content hash table of the file, and finally register the content hash table to the contract code hash table. Once that file is deployed to an arbitrary url, you can use admin.registerUrl to register the url with the content hash table on your blockchain (note that once the fixed content addressing pattern is used for the file store, the url-hint is no longer necessary).

source = "contract test { function multiply(uint a) returns(uint d) { return a
*
7; } }"
// compile with solc
contract = eth.compile.solidity(source).test
// create contract object
var MyContract = eth.contract(contract.info.abiDefinition)
// extracts info from contract, save the json serialisation in the given file,
contenthash = admin.saveInfo(contract.info, "~/dapps/shared/contracts/test/info.json")// send off the contract to the blockchain
MyContract.new({from: primaryAccount, data: contract.code}, function(error, contract){
if(!error && contract.address) {
// calculates the content hash and registers it with the code hash in `HashReg`
// it uses address to send the transaction.
// returns the content hash that we use to register a url
admin.register(primaryAccount, contract.address, contenthash)
// here you deploy ~/dapps/shared/contracts/test/info.json to a url
admin.registerUrl(primaryAccount, hash, url)
}
});

Test contracts and transactions

When troubleshooting trades and contracts, you will often need some low-level testing strategies. This chapter will introduce some troubleshooting tasks and practices that you can use. In order to test contracts and transactions without real consequences, it is best to test on a private blockchain. This can be achieved by configuring an alternate network ID (choose a special number) and/or an unavailable endpoint. It is recommended that for testing you use an alternate data directory and port so that it does not accidentally conflict with a live running node (assumes running by default. Enable geth in VM debug mode, performance analysis and maximum log verbosity are recommended remaining level):

geth --datadir ~/dapps/testing/00/ --port 30310 --rpcport 8110 --networkid 4567890 --nodiscover -

Before submitting a transaction, you need to create a private test chain (see the relevant chapter on test networks), for example:

// create account. will prompt for password
personal.newAccount();
// name your primary account, will often use it
primary = eth.accounts[0];
// check your balance (denominated in ether)
balance = web3.fromWei(eth.getBalance(primary), "ether");
 // assume an existing unlocked primary account
primary = eth.accounts[0];
// mine 10 blocks to generate ether
// starting miner
miner.start(4);
// sleep for 10 blocks (this can take quite some time).
admin.sleepBlocks(10);
// then stop mining (just not to burn heat in vain)
miner.stop();
balance = web3.fromWei(eth.getBalance(primary), "ether");

After creating the transaction, you can force it to run with the following command:

miner.start (1);
admin.sleepBlocks (1);
miner.stop ();

You can also view upcoming transactions with the following command:

// shows transaction pool
txpool.status
// number of pending txs
eth.getBlockTransactionCount(“pending”);
// print all pending txs
eth.getBlock(“pending”, true).transactions

If you submit a contract creation transaction, you can check that the desired code is actually embedded in the current blockchain:

txhash = eth.sendTansaction({from:primary, data: code})
//... mining
contractaddress = eth.getTransactionReceipt(txhash);
eth.getCode(contractaddress)

"Blockchain Development Guide" is edited by Shentu Qingchun, co-edited by Song Bo, Zhang Peng, Wang Xiaoming, Ji Zhoudong, Zuo Chuanmin, and recommended by Dajia of China's three major blockchain alliances.

write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325393660&siteId=291194637