Skip to content

Commit

Permalink
Merge pull request #578 from iotaledger/develop
Browse files Browse the repository at this point in the history
v0.2.2 release
  • Loading branch information
jorgemmsilva authored Nov 5, 2021
2 parents 3d7fb73 + 5a3a452 commit aca90a4
Show file tree
Hide file tree
Showing 572 changed files with 23,219 additions and 4,856 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ build-windows:

build-lint: build lint

test-full: install
go test -tags $(BUILD_TAGS),runheavy ./... --timeout 60m --count 1 -failfast

test: install
go test -tags $(BUILD_TAGS) ./... --timeout 30m --count 1 -failfast

Expand Down
2 changes: 1 addition & 1 deletion client/callview.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (c *WaspClient) CallView(chainID *iscp.ChainID, hContract iscp.Hname, funct
return res, err
case strings.Contains(err.Error(), "virtual state has been invalidated"):
if time.Now().After(deadline) {
return nil, coreutil.ErrStateHasBeenInvalidated
return nil, coreutil.ErrorStateInvalidated
}
time.Sleep(retryTimeoutOnOptimisticReadFail)
default:
Expand Down
6 changes: 2 additions & 4 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"

"golang.org/x/xerrors"

"github.com/iotaledger/wasp/packages/webapi/model"
"golang.org/x/xerrors"
)

// WaspClient allows to make requests to the Wasp web API.
Expand All @@ -32,7 +30,7 @@ func NewWaspClient(baseURL string, httpClient ...http.Client) *WaspClient {
}

func processResponse(res *http.Response, decodeTo interface{}) error {
resBody, err := ioutil.ReadAll(res.Body)
resBody, err := io.ReadAll(res.Body)
if err != nil {
return xerrors.Errorf("unable to read response body: %w", err)
}
Expand Down
110 changes: 110 additions & 0 deletions contracts/native/evm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# EVM support

This package and subpackages contain the code for the `evmchain` and `evmlight`
smart contracts, which allow to execute Ethereum VM (EVM) code on top of the
ISCP chain, thus adding support for Ethereum smart contracts.

## EVM flavors

There are two EVM 'flavors', each one being a native ISCP smart contract. You
must decide which one to use when deploying a new EVM chain:

### `evmchain`

The `evmchain` implementation emulates a full Ethereum blockchain, as if it
were an Ethereum 'node', storing the full history of blocks and past states.

Pros:
- More likely to be compatible with existing EVM tools (e.g.: Metamask, Remix,
Hardhat, etc.) that expect a 'real' Ethereum blockchain.

Cons:
- Inefficient: spends time and space calculating the Merkle tree, verifying
blocks, storing past states, etc, when none of this is necessary in an ISCP
contract.

### `evmlight`

The `evmlight` implementation is a more efficient solution for EVM support. It
stores only the current EVM state in raw form, and after running an Ethereum
transaction, it:

- Updates the EVM state
- Stores the transaction and receipt for future reference. Only the latest N
transactions/receipts are stored, to avoid using unlimited space.

Pros:
- More space/time efficient than `evmchain`
- Potentially easier to integrate with ISCP (still in experimental phase)

Cons:
- Less support for existing EVM tools that expect a 'real' Ethereum blockchain.
There is still partial support for some EVM tools. YMMV.

## Enabling / disabling EVM

EVM support is provided by the `evmchain` and `evmlight` native contracts, and
as such it needs to be enabled at compile time. **EVM support is enabled by
default, so no special action is needed.**

EVM support inflates the `wasp` and `wasp-cli` binaries by several MB. If this
is a problem and you don't need EVM support, you can disable it at compile
time by providing the `-tags noevm` flag to the Go compiler. For example:

```
go install -tags noevm ./...
```

## Deploy

You can use `wasp-cli` to deploy the `evmchain` or `evmlight` contract (given that you
already have access to an ISCP chain and have deposited some funds into your
on-chain account):

```
wasp-cli chain evm deploy --alloc 0x71562b71999873DB5b286dF957af199Ec94617F7:115792089237316195423570985008687907853269984665640564039457584007913129639927
```

The `--alloc` parameter specifies the genesis allocation for the EVM chain,
with syntax `address:wei [address:wei ...]`.

By default the `evmchain` contract will be deployed; you can change this with
`--evm-flavor evmlight`.

## JSON-RPC

Once your EVM chain is deployed, you can use the `wasp-cli chain evm jsonrpc`
command to start a JSON-RPC server. This will allow you to connect any standard
Ethereum tool, like Metamask.

Note: If you are using `evmlight` you should run the JSON-RPC server with
`--name evmlight`.

## Complete example using `wasp-cluster`

In terminal #1, start a cluster:

```
wasp-cluster start -d
```

In terminal #2:

```
# initialize a private key and request some funds
wasp-cli init
wasp-cli request-funds
# deploy an ISCP chain, deposit some funds to be used for fees
wasp-cli chain deploy --chain=mychain --committee=0,1,2,3 --quorum 3
wasp-cli chain deposit IOTA:1000
# deploy an EVM chain
wasp-cli chain evm deploy --alloc 0x71562b71999873DB5b286dF957af199Ec94617F7:115792089237316195423570985008687907853269984665640564039457584007913129639927
```

Finally we start the JSON-RPC server:

```
wasp-cli chain evm jsonrpc
```
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

package evm
package emulator

import (
"github.com/ethereum/go-ethereum/common"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

package evm
package emulator

import (
"testing"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

// package evm provides tools to emulate Ethereum chains and contracts.
// package emulator provides tools to emulate Ethereum chains and contracts.
//
// Code adapted from go-ethereum/accounts/abi/bind/backends/simulated.go
package evm
package emulator

import (
"context"
Expand All @@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/iotaledger/wasp/contracts/native/evm"
"golang.org/x/xerrors"
)

Expand All @@ -55,15 +56,11 @@ type EVMEmulator struct {
}

var (
TxGas = uint64(21000) // gas cost of simple transfer (not contract creation / call)
GasLimitDefault = uint64(15000000)
GasPrice = big.NewInt(0)
vmConfig = vm.Config{}
timeDelta = uint64(1) // amount of seconds to add to timestamp by default for new blocks
TxGas = uint64(21000) // gas cost of simple transfer (not contract creation / call)
vmConfig = vm.Config{}
timeDelta = uint64(1) // amount of seconds to add to timestamp by default for new blocks
)

const DefaultChainID = 1074 // IOTA -- get it?

func MakeConfig(chainID int) *params.ChainConfig {
return &params.ChainConfig{
ChainID: big.NewInt(int64(chainID)),
Expand Down Expand Up @@ -387,7 +384,7 @@ func (e *EVMEmulator) PendingNonceAt(account common.Address) (uint64, error) {
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
// chain doesn't have miners, we just return a gas price of 1 for any call.
func (e *EVMEmulator) SuggestGasPrice() (*big.Int, error) {
return GasPrice, nil
return evm.GasPrice, nil
}

// EstimateGas executes the requested code against the currently pending block/state and
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

package evm
package emulator

import (
"crypto/ecdsa"
Expand All @@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/iotaledger/wasp/contracts/native/evm"
"github.com/iotaledger/wasp/packages/evm/evmtest"
"github.com/iotaledger/wasp/packages/kv"
"github.com/iotaledger/wasp/packages/kv/dict"
Expand All @@ -32,7 +33,7 @@ func estimateGas(t testing.TB, emu *EVMEmulator, from common.Address, to *common
})
if err != nil {
t.Logf("%v", err)
return GasLimitDefault - 1
return evm.GasLimitDefault - 1
}
return gas
}
Expand All @@ -45,7 +46,7 @@ func sendTransaction(t testing.TB, emu *EVMEmulator, sender *ecdsa.PrivateKey, r
gas := estimateGas(t, emu, senderAddress, &receiverAddress, amount, data)

tx, err := types.SignTx(
types.NewTransaction(nonce, receiverAddress, amount, gas, GasPrice, data),
types.NewTransaction(nonce, receiverAddress, amount, gas, evm.GasPrice, data),
emu.Signer(),
sender,
)
Expand Down Expand Up @@ -89,7 +90,7 @@ func testBlockchain(t testing.TB, db ethdb.Database) {
faucetAddress: {Balance: faucetSupply},
}

InitGenesis(DefaultChainID, db, genesisAlloc, GasLimitDefault, 0)
InitGenesis(evm.DefaultChainID, db, genesisAlloc, evm.GasLimitDefault, 0)

emu := NewEVMEmulator(db)
defer emu.Close()
Expand All @@ -110,7 +111,7 @@ func testBlockchain(t testing.TB, db ethdb.Database) {
// assert that current block is genesis
block := emu.Blockchain().CurrentBlock()
require.NotNil(t, block)
require.EqualValues(t, GasLimitDefault, block.Header().GasLimit)
require.EqualValues(t, evm.GasLimitDefault, block.Header().GasLimit)
genesisHash = block.Hash()
}

Expand All @@ -137,7 +138,7 @@ func testBlockchain(t testing.TB, db ethdb.Database) {
sendTransaction(t, emu, faucet, receiverAddress, transferAmount, nil)

require.EqualValues(t, 1, emu.Blockchain().CurrentBlock().NumberU64())
require.EqualValues(t, GasLimitDefault, emu.Blockchain().CurrentBlock().Header().GasLimit)
require.EqualValues(t, evm.GasLimitDefault, emu.Blockchain().CurrentBlock().Header().GasLimit)
}

{
Expand Down Expand Up @@ -178,7 +179,7 @@ func testBlockchainPersistence(t testing.TB, db ethdb.Database) {
receiverAddress := crypto.PubkeyToAddress(receiver.PublicKey)
transferAmount := big.NewInt(1000)

InitGenesis(DefaultChainID, db, genesisAlloc, GasLimitDefault, 0)
InitGenesis(evm.DefaultChainID, db, genesisAlloc, evm.GasLimitDefault, 0)

// do a transfer using one instance of EVMEmulator
func() {
Expand Down Expand Up @@ -224,7 +225,7 @@ func deployEVMContract(t testing.TB, emu *EVMEmulator, creator *ecdsa.PrivateKey
require.NoError(t, err)

tx, err := types.SignTx(
types.NewContractCreation(nonce, txValue, gas, GasPrice, data),
types.NewContractCreation(nonce, txValue, gas, evm.GasPrice, data),
emu.Signer(),
creator,
)
Expand All @@ -239,7 +240,7 @@ func deployEVMContract(t testing.TB, emu *EVMEmulator, creator *ecdsa.PrivateKey
// assertions
{
require.EqualValues(t, 1, emu.Blockchain().CurrentBlock().NumberU64())
require.EqualValues(t, GasLimitDefault, emu.Blockchain().CurrentBlock().Header().GasLimit)
require.EqualValues(t, evm.GasLimitDefault, emu.Blockchain().CurrentBlock().Header().GasLimit)

// verify contract address
{
Expand Down Expand Up @@ -301,7 +302,7 @@ func testStorageContract(t testing.TB, db ethdb.Database) {
faucetAddress: {Balance: faucetSupply},
}

InitGenesis(DefaultChainID, db, genesisAlloc, GasLimitDefault, 0)
InitGenesis(evm.DefaultChainID, db, genesisAlloc, evm.GasLimitDefault, 0)

emu := NewEVMEmulator(db)
defer emu.Close()
Expand Down Expand Up @@ -374,7 +375,7 @@ func testERC20Contract(t testing.TB, db ethdb.Database) {
faucetAddress: {Balance: faucetSupply},
}

InitGenesis(DefaultChainID, db, genesisAlloc, GasLimitDefault, 0)
InitGenesis(evm.DefaultChainID, db, genesisAlloc, evm.GasLimitDefault, 0)

emu := NewEVMEmulator(db)
defer emu.Close()
Expand Down Expand Up @@ -467,7 +468,7 @@ func initBenchmark(b *testing.B) (*EVMEmulator, []*types.Transaction, dict.Dict)
faucetAddress: {Balance: faucetSupply},
}

InitGenesis(DefaultChainID, db, genesisAlloc, GasLimitDefault, 0)
InitGenesis(evm.DefaultChainID, db, genesisAlloc, evm.GasLimitDefault, 0)

emu := NewEVMEmulator(db)
defer emu.Close()
Expand Down Expand Up @@ -499,7 +500,7 @@ func initBenchmark(b *testing.B) (*EVMEmulator, []*types.Transaction, dict.Dict)
gas := estimateGas(b, emu, senderAddress, &contractAddress, amount, callArguments)

txs[i], err = types.SignTx(
types.NewTransaction(nonce, contractAddress, amount, gas, GasPrice, callArguments),
types.NewTransaction(nonce, contractAddress, amount, gas, evm.GasPrice, callArguments),
emu.Signer(),
sender,
)
Expand Down
Loading

0 comments on commit aca90a4

Please sign in to comment.