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 := ¶ms.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()
}