aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2019-08-15 18:49:42 -0400
committerDeterminant <ted.sybil@gmail.com>2019-08-15 18:49:42 -0400
commitff58d84f81d584646ca3f8fe00493cdcec8239ed (patch)
tree4b061596cc4c66c814e013aa91e74a27d9d0a9eb
parent669168d32a534c1054f9df659b3199f7b6da0d21 (diff)
add smart contract example
-rw-r--r--coreth.go4
-rw-r--r--examples/counter/counter.sol14
-rw-r--r--examples/counter/main.go153
-rw-r--r--examples/payments/main.go4
4 files changed, 173 insertions, 2 deletions
diff --git a/coreth.go b/coreth.go
index 84a6b59..a164452 100644
--- a/coreth.go
+++ b/coreth.go
@@ -106,6 +106,10 @@ func (self *ETHChain) SetHead(hash common.Hash) error {
return self.backend.BlockChain().FastSyncCommitHead(hash)
}
+func (self *ETHChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
+ return self.backend.BlockChain().GetReceiptsByHash(hash)
+}
+
type Key struct {
Address common.Address
PrivateKey *ecdsa.PrivateKey
diff --git a/examples/counter/counter.sol b/examples/counter/counter.sol
new file mode 100644
index 0000000..c05bf23
--- /dev/null
+++ b/examples/counter/counter.sol
@@ -0,0 +1,14 @@
+pragma solidity ^0.5.10;
+
+contract Counter {
+ uint256 x;
+
+ constructor() public {
+ x = 42;
+ }
+
+ function add(uint256 y) public returns (uint256) {
+ x = x + y;
+ return x;
+ }
+}
diff --git a/examples/counter/main.go b/examples/counter/main.go
new file mode 100644
index 0000000..662fea1
--- /dev/null
+++ b/examples/counter/main.go
@@ -0,0 +1,153 @@
+package main
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "github.com/ava-labs/coreth"
+ "github.com/ava-labs/coreth/eth"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/compiler"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/params"
+ "math/big"
+ "os"
+ "os/signal"
+ "path/filepath"
+ "syscall"
+ "time"
+)
+
+func checkError(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+func main() {
+ // configure the chain
+ config := eth.DefaultConfig
+ chainConfig := &params.ChainConfig{
+ ChainID: big.NewInt(1),
+ HomesteadBlock: big.NewInt(0),
+ DAOForkBlock: big.NewInt(0),
+ DAOForkSupport: true,
+ EIP150Block: big.NewInt(0),
+ EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
+ EIP155Block: big.NewInt(0),
+ EIP158Block: big.NewInt(0),
+ ByzantiumBlock: big.NewInt(0),
+ ConstantinopleBlock: big.NewInt(0),
+ PetersburgBlock: big.NewInt(0),
+ IstanbulBlock: nil,
+ Ethash: nil,
+ }
+
+ // configure the genesis block
+ genBalance := big.NewInt(100000000000000000)
+ genKey, _ := coreth.NewKey(rand.Reader)
+
+ config.Genesis = &core.Genesis{
+ Config: chainConfig,
+ Nonce: 0,
+ Number: 0,
+ ExtraData: hexutil.MustDecode("0x00"),
+ GasLimit: 100000000,
+ Difficulty: big.NewInt(0),
+ Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}},
+ }
+
+ // grab the control of block generation and disable auto uncle
+ config.Miner.ManualMining = true
+ config.Miner.ManualUncle = true
+
+ // compile the smart contract
+ counterSrc, err := filepath.Abs("./counter.sol")
+ checkError(err)
+ contracts, err := compiler.CompileSolidity("", counterSrc)
+ checkError(err)
+ contract, _ := contracts[fmt.Sprintf("%s:%s", counterSrc, "Counter")]
+
+ // info required to generate a transaction
+ chainID := chainConfig.ChainID
+ nonce := uint64(0)
+ gasLimit := 10000000
+ gasPrice := big.NewInt(1000000000)
+
+ blockCount := 0
+ chain := coreth.NewETHChain(&config, nil)
+ firstBlock := false
+ var contractAddr common.Address
+ postGen := func(block *types.Block) bool {
+ if blockCount == 15 {
+ state, err := chain.CurrentState()
+ checkError(err)
+ log.Info(fmt.Sprintf("genesis balance = %s", state.GetBalance(genKey.Address)))
+ log.Info(fmt.Sprintf("contract balance = %s", state.GetBalance(contractAddr)))
+ log.Info(fmt.Sprintf("state = %s", state.Dump(true, false, true)))
+ log.Info(fmt.Sprintf("x = %s", state.GetState(contractAddr, common.BigToHash(big.NewInt(0))).String()))
+ return true
+ }
+ if !firstBlock {
+ firstBlock = true
+ receipts := chain.GetReceiptsByHash(block.Hash())
+ if len(receipts) != 1 {
+ panic("# receipts is not 1")
+ }
+ contractAddr = receipts[0].ContractAddress
+ txHash := receipts[0].TxHash
+ log.Info(fmt.Sprintf("deploy tx = %s", txHash.String()))
+ log.Info(fmt.Sprintf("contract addr = %s", contractAddr.String()))
+ call := common.Hex2Bytes("1003e2d20000000000000000000000000000000000000000000000000000000000000001")
+ state, _ := chain.CurrentState()
+ log.Info(fmt.Sprintf("code = %s", hex.EncodeToString(state.GetCode(contractAddr))))
+ go func() {
+ for i := 0; i < 10; i++ {
+ tx := types.NewTransaction(nonce, contractAddr, big.NewInt(0), uint64(gasLimit), gasPrice, call)
+ signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey)
+ checkError(err)
+ chain.AddRemoteTxs([]*types.Transaction{signedTx})
+ time.Sleep(1000 * time.Millisecond)
+ nonce++
+ }
+ }()
+ }
+ return false
+ }
+ chain.SetOnSeal(func(block *types.Block) error {
+ go func() {
+ // the minimum time gap is 1s
+ time.Sleep(1000 * time.Millisecond)
+ // generate 15 blocks
+ blockCount++
+ if postGen(block) {
+ return
+ }
+ chain.GenBlock()
+ }()
+ return nil
+ })
+
+ // start the chain
+ chain.Start()
+
+ _ = contract
+ code := common.Hex2Bytes(contract.Code[2:])
+ tx := types.NewContractCreation(nonce, big.NewInt(0), uint64(gasLimit), gasPrice, code)
+ signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey)
+ checkError(err)
+ chain.AddRemoteTxs([]*types.Transaction{signedTx})
+ time.Sleep(1000 * time.Millisecond)
+ nonce++
+
+ chain.GenBlock()
+
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+ signal.Notify(c, os.Interrupt, syscall.SIGINT)
+ <-c
+ chain.Stop()
+}
diff --git a/examples/payments/main.go b/examples/payments/main.go
index 1c0a18e..db43319 100644
--- a/examples/payments/main.go
+++ b/examples/payments/main.go
@@ -76,8 +76,8 @@ func main() {
showBalance := func() {
state, err := chain.CurrentState()
checkError(err)
- log.Info(fmt.Sprintf("genesis balanche = %s", state.GetBalance(genKey.Address)))
- log.Info(fmt.Sprintf("bob's balanche = %s", state.GetBalance(bob.Address)))
+ log.Info(fmt.Sprintf("genesis balance = %s", state.GetBalance(genKey.Address)))
+ log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bob.Address)))
}
chain.SetOnSeal(func(block *types.Block) error {
go func() {