神刀安全网

Ethereum Smart Contracts and Static Pages

Introduction

It was exactly two weeks ago, when I was with an old friend on the phone and he introduced ethereum to me. The conversation went like this: "Hey, do you have a day or two to hack something fun?" – "Yeah, why not". Two weeks later, I had finished what he asked me for. I cannot really say here what I was doing, because its confidential, but I can talk about the things I learned along the way and can introduce a few things. Things which are important to newcomers at the DApps-Land.

What Are We Going To Do?

First, I will cover some misconceptions to people who are completely new. Then I will show some basic stuff you can do with Solidity. Then we will deploy a simple contract and try to call a function from an angular app. This should be enough for this tutorial. In the next tutorial we are going to see how events work and how we can call a contract from another contract and send an ether-value (with address.call.value()() – my new favorite).

Ethereum, Blockchain, Clients and JavaScript

It was very difficult for me to understand (and see the difference between) the terms

  • Web3
  • Solidity
  • Blockchain
  • Geth
  • CPP-Ethereum
  • Homestead

The two documentations you should at least have open in a tab:

Web3

Web3 is, as far as I understand, meant as a library of JavaScript functions. It’s a library actually. When you use bower for your projects you could do like bower install --save web3 and it would install the web3-js library. Then you can do things like

var web3 = new Web3();  web3.sha3('test123()');

You can also do other things, which I will cover in the next chapter below.

GETH and CPP-Ethereum and Others

The Ethereum Blockchain has to be accessed by clients. And all of those are clients do (more or less) exactly the same. GETH (Go-Ethereum) is written in go and does the same as CPP-Ethereum (written in C++). The only major difference is that with CPP-Ethereum there is AlethZero and Mix included. Which you might need, or not. See here for an overview.

I had major troubles getting CPP-Ethereum (and Mix and AlethZero) to run. I was running Windows 10 at that time, so maybe it was the reason. Although I saw the same problems on a Mac. The programs just kept crashing.

On the other hand, once AlethZero is running it is an ease to setup a private chain to try around with Contracts. Mix is supposed to be an IDE, but its really in its infanties from my point of view.

In order to connect to the blockchain you need to open GETH or CPP-Ethereum, which is  nothing else than a node downloading all blocks. Yes, all blocks. The blockchain is a state-machine and every time a transaction takes place the state is updated. So, you can always see at which block what transaction took place. Back to the origin.

Solidity, Serpent and Others

Solidity, Serpent and others are high-level languages you can write DApps in (DApps = Distributed apps). In order to let DApps "run" they are getting compiled into EVM . You don’t have to write in Solidity, you can also write it in other languages , but your best choice at the moment is probably Solidity. There are numerous "IDE"s (well, more like editors with a few benefits) you can write your DApps in. If you are used to Visual Studio, IntelliJ or something similar, you probably have to wait a bit.

  • Browser-Solidity
    With the Browser Solidity you can directly write your DApps in the Browser. They get compiled and a blockchain is simulated. It works but not really good in my opinion.
  • Mix
    This was supposed to be THE IDE for Solidity until the whole CPP Ethereum Project got less attention than the Go-Ethereum Project. As mentioned above it kept crashing, but nevertheless, once its running, its useful. Ethereum Smart Contracts and Static Pages
  • NotePad
    You can also program your contracts in the notepad. They can be compiled afterwards.

Once the source is compiled it cannot be "de-compiled" into the high-level source code back. What you see is something similar like assembler language – and every instruction costs "gas".

Homestead, Frontier, Testnet

Those are releases of the Ethereum Blockchain. The current one is Homestead, the last one Frontier. When you read current documentation, be careful if that was written for Homestead. Sometimes, or mostly things also work from the documentation written for Frontier, but be careful.

A Simple Contract Example?

In this chapter we cover the following details:

  1. How to write a simple contract (there are already plenty of tutorials out there)
  2. How to deploy that contract on the live-chain
  3. How to connect a simple angular app to the contract and query some data

You probably have seen the very simple example in the Solidity Documentation. Lets stick with this example a bit.

Open up your Browser-Solidity and copy and paste the code in. Here is the code again for reference:

contract SimpleStorage {     uint storedData;      function set(uint x) {         storedData = x;     }      function get() constant returns (uint retVal) {         return storedData;     } }

lets extend it and add a kill functionality and a constructor. I will not cover here how the things work, please read the Solidity documentation – it is explained there extensively. What I will cover are the missing parts: how to make use of this from a static website hosted on github pages.

contract SimpleStorage {

uint storedData;

address creator;

function set(uint x) {

storedData = x;

}

function SimpleStorage() {

creator = msg.sender;

}

function get() constant returns (uint retVal) {

return storedData;

}

function kill() {

if(msg.sender == creator) { suicide(creator); }

}

}

How can we access this contract now? And how can we deploy it?

There are probably several ways to do that. I have tried to test-deploy my contracts with AlethZero in a test-blockchain but I utterly failed – it will just silently make contracts disappear.

I have also tried to "simulate" a read/write with the browser-solidity tool. You can actually do that, but at some point it just stopped working – especially for bigger contracts.

The only really easy way I found was deploying my contract using MIST in the live-blockchain. After debugging it with MIX or browser-solidity I mostly deployed it directly and saw how it will work. You find all the information you need for accounts and ways to access accounts in the official documentation. It is also mentioned there that MIST is beta-ware . Yes, I can confirm this. But nevertheless, it looks beautiful, mostly works and makes deploying contracts a breeze – on the live blockchain.

Deploy using MIST – The Ethereum Wallet

You can just download the wallet and open it. It will takes ages. It will download the whole blockchain. At the time of writing, on my 100MBit/s connection, it would take probably close to 10h – maybe it has changed already. The only way I found to get around is installing GETH and running it with the following commands:

geth --fast --cache=1024 --jitvm

and if you already have downloaded like 10%, just remove the whole db first and then run geth:

geth removedb
geth --fast --cache=1024 --jitvm

after that it should download the chain within 1-2h.

When you want to publish a contract you can do that by clicking on "Contracts" (on the right – written here "Verträge" – the german version) and then copy&paste the Solidity Sourcecode. And publish.

Ethereum Smart Contracts and Static Pages

Copy and paste the SimpleStorage Contract (including the kill() function) there and publish it.

What you get is an address. The contract is now reachable via an address.

Web3 Library via a local Json RPC

Now the normal way to work with web3 seems to be via a local HTTP Provider. You could do something like this:

var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

You have probably seen it multiple times.

It is a lot of fun to work with Javascript that way. In order to make use of the localhost:8545 I ran into multiple problems.

  1. GETH doesn’t open the http RPC by default.
  2. Firefox will complain when using with gulp angular (localhost port 3000)

to circumvent that problem you have to start GETH with the correct parameters:

geth --rpc --rpccorsdomain "http://localhost:3000"

ABI

The ABI is the Interface. When the contract is deployed the web3 library must know (in advance) what parameters and functions are available – and what is returned. To know that, there is a json-interface that looks like this:

[{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[],"type":"constructor"}]

and the whole contract could be deployed with a command like this:

var simplestorageContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[],"type":"constructor"}]);  var simplestorage = simplestorageContract.new(     {       from: web3.eth.accounts[0],       data: '606060[...]444',       gas: 3000000     }, function(e, contract){      console.log(e, contract);      if (typeof contract.address != 'undefined') {           console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);      }   });

You cannot really copy and paste it, I abbrevated the "data" field, but you get the idea probably.

If the contract is already deployed then you can simple use it in web3. It looks almost the same as the ABI definition itself – mind the difference. If you have the local GETH RPC running, you can just simply add the existing contract you published in the previous chapter to your Javascript Web3. Use

var simplestorageContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[],"type":"constructor"}]).address(your_address_you_deployed_earlier);

Then you can do things like

console.log(simplestorageContract.get());

Super simple :) But here is the caveat:

That only works when you have a local (or remote) HttpProvider for web3.And to my best knowledge, there is no public HttpProvider. You have to download geth (or cpp-ethereum) and run it yourself. On your server. Which is really annoying if you want to deploy to github pages. What comes in handy is the API from Etherscan.

Etherscan.io API

The guys from etherscan have built an API around that . But it is a bit tricky to access it – for newcomers.

While getting account-balance information is relatively easy, it becomes harder to access functions. Basically you can only access functions that are declared as "constant". Because such functions do not require any gas – they just return a value.

Lets say the address from your SimpleStorage contract is 0x111222DEADBEEF then you could query the balance for the account like this:

https://api.etherscan.io/api?module=account&action=balance&address=0x111222DEADBEEF&tag=latest

Without any APIKey Etherscan will allow somewhat 5 requests per second. That is what they write on their website – no idea if that is by IP or address or action.

Functioncalls via Etherscan API

Before we can access functions in Etherscan, we have to know how to call functions in web3 natively.

In order to call functions in web3 natively, you have to take the first 4 bytes from the Keccak Hash and hex encode it. Sidenote: The example in the link doesn’t work properly, because web3 automatically adds the 0x for hex encoding.

Example – OUTPUT Parameter

Our ABI Interface from our sample contract sais the function "get" takes no inputs but returns one uint256 as output.

... {"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"} ...

that means, we can access it (in angular) JS like this:

var web3 = new Web3();  var functioncall = web3.sha3('get()').substring(0,10);

And then we can call the Etherscan API with the $http object in AngularJS easily.

$http({     method: "GET",     url: "https://api.etherscan.io/api?module=proxy&action=eth_call&to=" + self.getAddress() + "&data=" + web3.sha3("get()").substring(0, 10) }).then(function resultSuccess(payload) {     var storedData = web3.toDecimal(payload.data.result);     //do something with storedData from the contract }, function resultError(payload) {     console.log(payload); });

What do we see here?

we call an etherscan url for an "eth_call" action and call the "get" function from our SampleContract when "self.getAddress()" is returning the correct address. I will expand this sample in the second blog post, but for now it should really help you to get along.

"get" returns an uint256 and this can be transformed into a normal integer with web3.toDecimal(the_payload) as seen in the sample. Retrieving values doesn’t cost gas or anything, that is why this can be done via the web API without the need to send GAS.

Example – INPUT Parameter

We have another function in our SampleContract that is called "set". From the ABI Definition it sais:

{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"}...

it sais that it takes one uint256 as input parameter. While the example shown here will not work with the etherscan api, because you would have to add some gas, it shows you something else: How to properly encode the payload data manually.

Again from this page we can read, that we have to pad our input parameter with 32 bytes. While my padding version is probably not the nicest one, it will do the job:

function getPayload(some_uint) {     var padding = "0000000000000000000000000000000000000000000000000000000000000000";     return padding.substring(0,64 - web3.toHex(some_uint).substring(2).length)+web3.toHex(some_uint).substring(2); }

What happens here:

The whole hex-string has to be padded to reach 32 bytes (64 times "0").

web3.toHex(5) delivers 0x5 – we want to part after "0x" – so we take the substring from the second character on, which is "5".

and then we put the things together and return the value.

Then we need to construct the payload. We still need the function call Keccak Hashed. But this time we need to hash "set(uint256)", because the "set" function takes one uint256.

var data_payload = web3.sha3('set(uint256)').substring(0,10) + getPayload(1234); console.log(data_payload);

You could use this payload in your MIST wallet. Just send 0 ether and some gas to your created SampleContract and it will change the storedData. Aftewards you can use the Example above for the output parameter to get that value from the etherscan API.

Next Steps

In the next tutorial, which I have planned for mid July 2016, I will cover a simple example with angular JS. Most of the parts are covered here already, which should let you connect some dots and pieces. I hope you could understand how to access functions from your angular app and how to create payload properly. Let me know in the comments if you have any questions.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Ethereum Smart Contracts and Static Pages

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址