2

I am trying to add this simple test contract dumb.sol to my genesis.json file.

pragma solidity <0.8.6;

contract Dumb {
    string public name;
    string public symbol;

    constructor() {
        name = "Hello World";
        symbol = "HLW";
    }
}

I precompiled the contract with solc --bin-runtime ../contracts/dumb.sol -o precompiled_dumb

This created the precompiled_dumb/Dumb.bin-runtime file

(The reason I used the runtime-compiled bytecodes instead of the normal-compiled bytecode is that I tried the normal-compiled bytecode before and it doesn't work as well and due to an answer (whether correct or not) in this post Is it possible to preload contracts in the genesis block?, so I try to use the runtime-compiled bytecodes, but it still didn't work)

I then copied the runtime-compiled bytecodes in the precompiled_dumb/Dumb.bin-runtime and put into genesis.json file (generated by puppeth) at the alloc field at address 0x0000000000000000000000000000000000001234 like this

{
  "config": {
    "chainId": 32866,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "clique": {
      "period": 5,
      "epoch": 30000
    }
  },
  "nonce": "0x0",
  "timestamp": "0x60c9d775",
  "extraData": "0x000000000000000000000000000000000000000000000000000000000000000032d3751cc684d55f0b6deb73c4cc4c5ca499f3a6897ae8e5de375c65976323b82b0e318808f2bb0cbebb242cda3258cf98f74a5aa6424dd3ccf3d39a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x47b760",
  "difficulty": "0x1",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "alloc": {
    "0x32D3751cC684D55f0B6DEb73C4cC4C5ca499F3a6": {
      "balance": "0x200000000000000000000000000000000000000000000000000000000000000"
    },
    "0x0000000000000000000000000000000000001234": {
      "balance": "0x0",
      "code": 
      "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b57806395d89b4114610059575b600080fd5b610043610077565b60405161005091906101cc565b60405180910390f35b610061610105565b60405161006e91906101cc565b60405180910390f35b600080546100849061023d565b80601f01602080910402602001604051908101604052809291908181526020018280546100b09061023d565b80156100fd5780601f106100d2576101008083540402835291602001916100fd565b820191906000526020600020905b8154815290600101906020018083116100e057829003601f168201915b505050505081565b600180546101129061023d565b80601f016020809104026020016040519081016040528092919081815260200182805461013e9061023d565b801561018b5780601f106101605761010080835404028352916020019161018b565b820191906000526020600020905b81548152906001019060200180831161016e57829003601f168201915b505050505081565b600061019e826101ee565b6101a881856101f9565b93506101b881856020860161020a565b6101c18161029e565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561022857808201518184015260208101905061020d565b83811115610237576000848401525b50505050565b6000600282049050600182168061025557607f821691505b602082108114156102695761026861026f565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f830116905091905056fea2646970667358221220901fa5c7cc6385a9ab8f81aaea16e8139ce566f183bc20ec15a477002c06d46864736f6c63430008050033"
    }

  },
  "number": "0x0",
  "gasUsed": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

Then I use the abigen to generate the corresponding go file

solc --abi --bin  ../contracts/dumb.sol -o dumb_build
abigen --bin=./dumb_build/Dumb.bin --abi=./dumb_build/Dumb.abi --pkg=dumb --out=dumb/Dumb.go

This creates the true build file of the dumb.sol (not the runtime one like above) and then used it to auto-generate the dumb/Dumb.go file like below

// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.

package dumb

import (
    "math/big"
    "strings"

    ethereum "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/event"
)

// Reference imports to suppress errors if they are not otherwise used.
var (
    _ = big.NewInt
    _ = strings.NewReader
    _ = ethereum.NotFound
    _ = bind.Bind
    _ = common.Big1
    _ = types.BloomLookup
    _ = event.NewSubscription
)

// DumbABI is the input ABI used to generate the binding from.
const DumbABI = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]"

// DumbBin is the compiled bytecode used for deploying new contracts.
var DumbBin = "0x608060405234801561001057600080fd5b506040518060400160405280600b81526020017f48656c6c6f20576f726c640000000000000000000000000000000000000000008152506000908051906020019061005c9291906100ae565b506040518060400160405280600381526020017f484c570000000000000000000000000000000000000000000000000000000000815250600190805190602001906100a89291906100ae565b506101b2565b8280546100ba90610151565b90600052602060002090601f0160209004810192826100dc5760008555610123565b82601f106100f557805160ff1916838001178555610123565b82800160010185558215610123579182015b82811115610122578251825591602001919060010190610107565b5b5090506101309190610134565b5090565b5b8082111561014d576000816000905550600101610135565b5090565b6000600282049050600182168061016957607f821691505b6020821081141561017d5761017c610183565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6102e5806101c16000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b57806395d89b4114610059575b600080fd5b610043610077565b60405161005091906101cc565b60405180910390f35b610061610105565b60405161006e91906101cc565b60405180910390f35b600080546100849061023d565b80601f01602080910402602001604051908101604052809291908181526020018280546100b09061023d565b80156100fd5780601f106100d2576101008083540402835291602001916100fd565b820191906000526020600020905b8154815290600101906020018083116100e057829003601f168201915b505050505081565b600180546101129061023d565b80601f016020809104026020016040519081016040528092919081815260200182805461013e9061023d565b801561018b5780601f106101605761010080835404028352916020019161018b565b820191906000526020600020905b81548152906001019060200180831161016e57829003601f168201915b505050505081565b600061019e826101ee565b6101a881856101f9565b93506101b881856020860161020a565b6101c18161029e565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561022857808201518184015260208101905061020d565b83811115610237576000848401525b50505050565b6000600282049050600182168061025557607f821691505b602082108114156102695761026861026f565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000601f19601f830116905091905056fea2646970667358221220901fa5c7cc6385a9ab8f81aaea16e8139ce566f183bc20ec15a477002c06d46864736f6c63430008050033"

// DeployDumb deploys a new Ethereum contract, binding an instance of Dumb to it.
func DeployDumb(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Dumb, error) {
    parsed, err := abi.JSON(strings.NewReader(DumbABI))
    if err != nil {
        return common.Address{}, nil, nil, err
    }

    address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(DumbBin), backend)
    if err != nil {
        return common.Address{}, nil, nil, err
    }
    return address, tx, &Dumb{DumbCaller: DumbCaller{contract: contract}, DumbTransactor: DumbTransactor{contract: contract}, DumbFilterer: DumbFilterer{contract: contract}}, nil
}

// Dumb is an auto generated Go binding around an Ethereum contract.
type Dumb struct {
    DumbCaller     // Read-only binding to the contract
    DumbTransactor // Write-only binding to the contract
    DumbFilterer   // Log filterer for contract events
}

// DumbCaller is an auto generated read-only Go binding around an Ethereum contract.
type DumbCaller struct {
    contract *bind.BoundContract // Generic contract wrapper for the low level calls
}

// DumbTransactor is an auto generated write-only Go binding around an Ethereum contract.
type DumbTransactor struct {
    contract *bind.BoundContract // Generic contract wrapper for the low level calls
}

// DumbFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type DumbFilterer struct {
    contract *bind.BoundContract // Generic contract wrapper for the low level calls
}

// DumbSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type DumbSession struct {
    Contract     *Dumb             // Generic contract binding to set the session for
    CallOpts     bind.CallOpts     // Call options to use throughout this session
    TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}

// DumbCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type DumbCallerSession struct {
    Contract *DumbCaller   // Generic contract caller binding to set the session for
    CallOpts bind.CallOpts // Call options to use throughout this session
}

// DumbTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type DumbTransactorSession struct {
    Contract     *DumbTransactor   // Generic contract transactor binding to set the session for
    TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}

// DumbRaw is an auto generated low-level Go binding around an Ethereum contract.
type DumbRaw struct {
    Contract *Dumb // Generic contract binding to access the raw methods on
}

// DumbCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type DumbCallerRaw struct {
    Contract *DumbCaller // Generic read-only contract binding to access the raw methods on
}

// DumbTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type DumbTransactorRaw struct {
    Contract *DumbTransactor // Generic write-only contract binding to access the raw methods on
}

// NewDumb creates a new instance of Dumb, bound to a specific deployed contract.
func NewDumb(address common.Address, backend bind.ContractBackend) (*Dumb, error) {
    contract, err := bindDumb(address, backend, backend, backend)
    if err != nil {
        return nil, err
    }
    return &Dumb{DumbCaller: DumbCaller{contract: contract}, DumbTransactor: DumbTransactor{contract: contract}, DumbFilterer: DumbFilterer{contract: contract}}, nil
}

// NewDumbCaller creates a new read-only instance of Dumb, bound to a specific deployed contract.
func NewDumbCaller(address common.Address, caller bind.ContractCaller) (*DumbCaller, error) {
    contract, err := bindDumb(address, caller, nil, nil)
    if err != nil {
        return nil, err
    }
    return &DumbCaller{contract: contract}, nil
}

// NewDumbTransactor creates a new write-only instance of Dumb, bound to a specific deployed contract.
func NewDumbTransactor(address common.Address, transactor bind.ContractTransactor) (*DumbTransactor, error) {
    contract, err := bindDumb(address, nil, transactor, nil)
    if err != nil {
        return nil, err
    }
    return &DumbTransactor{contract: contract}, nil
}

// NewDumbFilterer creates a new log filterer instance of Dumb, bound to a specific deployed contract.
func NewDumbFilterer(address common.Address, filterer bind.ContractFilterer) (*DumbFilterer, error) {
    contract, err := bindDumb(address, nil, nil, filterer)
    if err != nil {
        return nil, err
    }
    return &DumbFilterer{contract: contract}, nil
}

// bindDumb binds a generic wrapper to an already deployed contract.
func bindDumb(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
    parsed, err := abi.JSON(strings.NewReader(DumbABI))
    if err != nil {
        return nil, err
    }
    return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}

// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Dumb *DumbRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
    return _Dumb.Contract.DumbCaller.contract.Call(opts, result, method, params...)
}

// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Dumb *DumbRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
    return _Dumb.Contract.DumbTransactor.contract.Transfer(opts)
}

// Transact invokes the (paid) contract method with params as input values.
func (_Dumb *DumbRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
    return _Dumb.Contract.DumbTransactor.contract.Transact(opts, method, params...)
}

// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Dumb *DumbCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
    return _Dumb.Contract.contract.Call(opts, result, method, params...)
}

// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Dumb *DumbTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
    return _Dumb.Contract.contract.Transfer(opts)
}

// Transact invokes the (paid) contract method with params as input values.
func (_Dumb *DumbTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
    return _Dumb.Contract.contract.Transact(opts, method, params...)
}

// Name is a free data retrieval call binding the contract method 0x06fdde03.
//
// Solidity: function name() view returns(string)
func (_Dumb *DumbCaller) Name(opts *bind.CallOpts) (string, error) {
    var out []interface{}
    err := _Dumb.contract.Call(opts, &out, "name")

    if err != nil {
        return *new(string), err
    }

    out0 := *abi.ConvertType(out[0], new(string)).(*string)

    return out0, err

}

// Name is a free data retrieval call binding the contract method 0x06fdde03.
//
// Solidity: function name() view returns(string)
func (_Dumb *DumbSession) Name() (string, error) {
    return _Dumb.Contract.Name(&_Dumb.CallOpts)
}

// Name is a free data retrieval call binding the contract method 0x06fdde03.
//
// Solidity: function name() view returns(string)
func (_Dumb *DumbCallerSession) Name() (string, error) {
    return _Dumb.Contract.Name(&_Dumb.CallOpts)
}

// Symbol is a free data retrieval call binding the contract method 0x95d89b41.
//
// Solidity: function symbol() view returns(string)
func (_Dumb *DumbCaller) Symbol(opts *bind.CallOpts) (string, error) {
    var out []interface{}
    err := _Dumb.contract.Call(opts, &out, "symbol")

    if err != nil {
        return *new(string), err
    }

    out0 := *abi.ConvertType(out[0], new(string)).(*string)

    return out0, err

}

// Symbol is a free data retrieval call binding the contract method 0x95d89b41.
//
// Solidity: function symbol() view returns(string)
func (_Dumb *DumbSession) Symbol() (string, error) {
    return _Dumb.Contract.Symbol(&_Dumb.CallOpts)
}

// Symbol is a free data retrieval call binding the contract method 0x95d89b41.
//
// Solidity: function symbol() view returns(string)
func (_Dumb *DumbCallerSession) Symbol() (string, error) {
    return _Dumb.Contract.Symbol(&_Dumb.CallOpts)
}

I then initialized 3 go ethereum nodes from the genesis.json file connected with each other and wrote a simple go file to print out the name variable in the contract throught the auto-generated Name function in the dumb/Dumb.go file (this one) The Auto-generated Name function in the dumb/Dumb.go file

// Solidity: function name() view returns(string)
func (_Dumb *DumbCaller) Name(opts *bind.CallOpts) (string, error) {
    var out []interface{}
    err := _Dumb.contract.Call(opts, &out, "name")

    if err != nil {
        return *new(string), err
    }

    out0 := *abi.ConvertType(out[0], new(string)).(*string)

    return out0, err

}

The code in main.go

package main

import (
    "context"
    "fmt"
    "log"
    "test/test/dumb"

    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)
func main() {

    client, err := ethclient.Dial("http://localhost:3334")
    if err != nil {
        log.Fatalf("Oops! There was a problem", err)
    } else {
        fmt.Println("Success! you are connected to the Ethereum Network")
    }
    address := common.HexToAddress("0x0000000000000000000000000000000000001234")
    //instance, err := coin.NewCoin(address, client)
    instance, err := dumb.NewDumb(address, client)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("contract is loaded")

    header, err := client.HeaderByNumber(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    } else {
        fmt.Println("Total Blocks :", header.Number.String())
    }

    name, err := instance.Name(&bind.CallOpts{})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Name", name)
}

As we can see from the code I tried to print out the number of blocks and the name variable.

Real Results:

Success! you are connected to the Ethereum Network
contract is loaded
Total Blocks : 8
Name 

Expected Results:

Success! you are connected to the Ethereum Network
contract is loaded
Total Blocks : 8
Name Hello World

It seems the contract is loaded correctly (otherwise it will say there's no contract at the address) but the variable in it cannot be fetched. Could someone help me with this issue please. Thanks.

FYI Normal Deploy of the same contract after blockchain started works perfectly (expected results acheived) but didn't work at all with pre-compiled contract deployed in the genesis block.

Edit1 : Fetching numbers and functions returning numbers seem to work now after changing the using account to the node I'm getting the ipc from but fetching string still doesn't.

1
  • If you query the contract's bytecode what does it return? (web3.eth.getCode)
    – Ismael
    Jun 22, 2021 at 7:07

1 Answer 1

0

The constructor is not run in contracts defined in the genesis.json. I suppose the constructor is actually not even included in the --bin-runtime output. If you wish to initialize values at the genesis time, you have to use the storage parameter, e.g.

...
"alloc": {
    "0x0000000000000000000000000000000000001000": {
        "balance": "0x0",
        "code": "...",
        "storage": {
            "0x0000000000000000000000000000000000000000000000000000000000000001": "0x1",
            "0x0000000000000000000000000000000000000000000000000000000000000002": "0xa"
        }
    }
}
...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.