aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2020-06-30 17:05:50 -0400
committerDeterminant <[email protected]>2020-06-30 17:05:50 -0400
commit7feec02902d52a3abf722613eb9e218e015b723c (patch)
tree3ca683e866cdaba9c06480f825682677826557f3
parent3a872747058e9fd32810d0864e19a197529b7d79 (diff)
make mc tx work
-rw-r--r--core/evm.go7
-rw-r--r--core/gen_genesis.go2
-rw-r--r--core/gen_genesis_account.go8
-rw-r--r--core/genesis.go9
-rw-r--r--core/state/statedb.go5
-rw-r--r--core/tx_pool.go1
-rw-r--r--core/types/gen_tx_json.go12
-rw-r--r--core/types/transaction.go22
-rw-r--r--core/vm/evm.go2
-rw-r--r--eth/backend.go2
-rw-r--r--eth/gen_config.go12
-rw-r--r--eth/tracers/internal/tracers/assets.go37
-rw-r--r--examples/chain/main.go2
-rw-r--r--examples/counter/main.go2
-rw-r--r--examples/multicoin/main.go218
-rw-r--r--plugin/evm/static_service_test.go64
-rw-r--r--plugin/evm/vm_genesis_parse_test.go32
-rw-r--r--rpc/client_example_test.go88
-rw-r--r--rpc/client_test.go569
-rw-r--r--rpc/http_test.go54
-rw-r--r--rpc/server_test.go152
-rw-r--r--rpc/subscription_test.go206
-rw-r--r--rpc/testservice_test.go180
-rw-r--r--rpc/types_test.go66
-rw-r--r--rpc/websocket_test.go259
25 files changed, 297 insertions, 1714 deletions
diff --git a/core/evm.go b/core/evm.go
index ecab8e6..796b312 100644
--- a/core/evm.go
+++ b/core/evm.go
@@ -99,7 +99,7 @@ func CanTransferMC(db vm.StateDB, addr common.Address, to common.Address, coinID
}
if !db.IsMultiCoin(addr) {
err := db.EnableMultiCoin(addr)
- log.Debug("try to enable MC", "err", err)
+ log.Debug("try to enable MC", "addr", addr.Hex(), "err", err)
}
if !(db.IsMultiCoin(addr) && db.IsMultiCoin(to)) {
// incompatible
@@ -124,8 +124,5 @@ func TransferMultiCoin(db vm.StateDB, sender, recipient common.Address, coinID *
return
}
db.SubBalanceMultiCoin(sender, *coinID, amount)
- z := &big.Int{}
- z.Add(amount, big.NewInt(1000000000000000000))
- log.Info("hi")
- db.AddBalanceMultiCoin(recipient, *coinID, z)
+ db.AddBalanceMultiCoin(recipient, *coinID, amount)
}
diff --git a/core/gen_genesis.go b/core/gen_genesis.go
index 05883c0..97175f7 100644
--- a/core/gen_genesis.go
+++ b/core/gen_genesis.go
@@ -15,6 +15,7 @@ import (
var _ = (*genesisSpecMarshaling)(nil)
+// MarshalJSON marshals as JSON.
func (g Genesis) MarshalJSON() ([]byte, error) {
type Genesis struct {
Config *params.ChainConfig `json:"config"`
@@ -51,6 +52,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) {
return json.Marshal(&enc)
}
+// UnmarshalJSON unmarshals from JSON.
func (g *Genesis) UnmarshalJSON(input []byte) error {
type Genesis struct {
Config *params.ChainConfig `json:"config"`
diff --git a/core/gen_genesis_account.go b/core/gen_genesis_account.go
index a7ef4a6..b90b658 100644
--- a/core/gen_genesis_account.go
+++ b/core/gen_genesis_account.go
@@ -14,11 +14,13 @@ import (
var _ = (*genesisAccountMarshaling)(nil)
+// MarshalJSON marshals as JSON.
func (g GenesisAccount) MarshalJSON() ([]byte, error) {
type GenesisAccount struct {
Code hexutil.Bytes `json:"code,omitempty"`
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
+ MCBalance GenesisMultiCoinBalance `json:"mcbalance,omitempty"`
Nonce math.HexOrDecimal64 `json:"nonce,omitempty"`
PrivateKey hexutil.Bytes `json:"secretKey,omitempty"`
}
@@ -31,16 +33,19 @@ func (g GenesisAccount) MarshalJSON() ([]byte, error) {
}
}
enc.Balance = (*math.HexOrDecimal256)(g.Balance)
+ enc.MCBalance = g.MCBalance
enc.Nonce = math.HexOrDecimal64(g.Nonce)
enc.PrivateKey = g.PrivateKey
return json.Marshal(&enc)
}
+// UnmarshalJSON unmarshals from JSON.
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
type GenesisAccount struct {
Code *hexutil.Bytes `json:"code,omitempty"`
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
+ MCBalance *GenesisMultiCoinBalance `json:"mcbalance,omitempty"`
Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"`
PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"`
}
@@ -61,6 +66,9 @@ func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'balance' for GenesisAccount")
}
g.Balance = (*big.Int)(dec.Balance)
+ if dec.MCBalance != nil {
+ g.MCBalance = *dec.MCBalance
+ }
if dec.Nonce != nil {
g.Nonce = uint64(*dec.Nonce)
}
diff --git a/core/genesis.go b/core/genesis.go
index 347beb3..ef490bf 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -78,11 +78,14 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
return nil
}
+type GenesisMultiCoinBalance map[common.Hash]*big.Int
+
// GenesisAccount is an account in the state of the genesis block.
type GenesisAccount struct {
Code []byte `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
Balance *big.Int `json:"balance" gencodec:"required"`
+ MCBalance GenesisMultiCoinBalance `json:"mcbalance,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
}
@@ -261,6 +264,12 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
for key, value := range account.Storage {
statedb.SetState(addr, key, value)
}
+ if account.MCBalance != nil {
+ statedb.ForceEnableMultiCoin(addr)
+ for coinID, value := range account.MCBalance {
+ statedb.AddBalanceMultiCoin(addr, coinID, value)
+ }
+ }
}
root := statedb.IntermediateRoot(false)
head := &types.Header{
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 12deebe..1d3207d 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -248,6 +248,11 @@ func (self *StateDB) EnableMultiCoin(addr common.Address) error {
return nil
}
+func (self *StateDB) ForceEnableMultiCoin(addr common.Address) {
+ stateObject := self.GetOrNewStateObject(addr)
+ stateObject.EnableMultiCoin()
+}
+
func (self *StateDB) IsMultiCoin(addr common.Address) bool {
stateObject := self.getStateObject(addr)
if stateObject != nil {
diff --git a/core/tx_pool.go b/core/tx_pool.go
index 1acd488..5b2a3c0 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -528,7 +528,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
}
// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() {
- fmt.Println(pool.currentMaxGas, tx.Gas())
return ErrGasLimit
}
// Make sure the transaction is signed properly
diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go
index 0410632..dd0d069 100644
--- a/core/types/gen_tx_json.go
+++ b/core/types/gen_tx_json.go
@@ -21,6 +21,8 @@ func (t txdata) MarshalJSON() ([]byte, error) {
GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"`
Amount *hexutil.Big `json:"value" gencodec:"required"`
+ CoinID *common.Hash `json:"coinid" rlp:"nil"`
+ Amount2 *hexutil.Big `json:"value2" rlp:"nil"`
Payload hexutil.Bytes `json:"input" gencodec:"required"`
V *hexutil.Big `json:"v" gencodec:"required"`
R *hexutil.Big `json:"r" gencodec:"required"`
@@ -33,6 +35,8 @@ func (t txdata) MarshalJSON() ([]byte, error) {
enc.GasLimit = hexutil.Uint64(t.GasLimit)
enc.Recipient = t.Recipient
enc.Amount = (*hexutil.Big)(t.Amount)
+ enc.CoinID = t.CoinID
+ enc.Amount2 = (*hexutil.Big)(t.Amount2)
enc.Payload = t.Payload
enc.V = (*hexutil.Big)(t.V)
enc.R = (*hexutil.Big)(t.R)
@@ -49,6 +53,8 @@ func (t *txdata) UnmarshalJSON(input []byte) error {
GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"`
Amount *hexutil.Big `json:"value" gencodec:"required"`
+ CoinID *common.Hash `json:"coinid" rlp:"nil"`
+ Amount2 *hexutil.Big `json:"value2" rlp:"nil"`
Payload *hexutil.Bytes `json:"input" gencodec:"required"`
V *hexutil.Big `json:"v" gencodec:"required"`
R *hexutil.Big `json:"r" gencodec:"required"`
@@ -78,6 +84,12 @@ func (t *txdata) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'value' for txdata")
}
t.Amount = (*big.Int)(dec.Amount)
+ if dec.CoinID != nil {
+ t.CoinID = dec.CoinID
+ }
+ if dec.Amount2 != nil {
+ t.Amount2 = (*big.Int)(dec.Amount2)
+ }
if dec.Payload == nil {
return errors.New("missing required field 'input' for txdata")
}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index cf9e61a..858b443 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -49,8 +49,8 @@ type txdata struct {
GasLimit uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value" gencodec:"required"`
- CoinID *common.Hash `json:"coinid" rlp:"-"`
- Amount2 *big.Int `json:"value2"`
+ CoinID *common.Hash `json:"coinid" rlp:"nil"`
+ Amount2 *big.Int `json:"value2" rlp:"nil"`
Payload []byte `json:"input" gencodec:"required"`
// Signature values
@@ -67,7 +67,7 @@ type txdataMarshaling struct {
Price *hexutil.Big
GasLimit hexutil.Uint64
Amount *hexutil.Big
- CoinID *hexutil.Bytes
+ CoinID *common.Hash
Amount2 *hexutil.Big
Payload hexutil.Bytes
V *hexutil.Big
@@ -183,14 +183,14 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
return nil
}
-func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
-func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
-func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
-func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
-func (tx *Transaction) CoinID() *big.Int { return big.NewInt(0) }
-func (tx *Transaction) Value2() *big.Int { return big.NewInt(0) }
-func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
-func (tx *Transaction) CheckNonce() bool { return true }
+func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
+func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
+func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
+func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
+func (tx *Transaction) CoinID() *common.Hash { return tx.data.CoinID }
+func (tx *Transaction) Value2() *big.Int { return new(big.Int).Set(tx.data.Amount2) }
+func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
+func (tx *Transaction) CheckNonce() bool { return true }
// To returns the recipient address of the transaction.
// It returns nil if the transaction is a contract creation.
diff --git a/core/vm/evm.go b/core/vm/evm.go
index ff3587c..be8b240 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -17,7 +17,6 @@
package vm
import (
- "fmt"
"math/big"
"sync/atomic"
"time"
@@ -260,7 +259,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// This allows the user transfer balance of a specified coinId in addition to a normal Call().
func (evm *EVM) CallExpert(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, coinID *common.Hash, value2 *big.Int) (ret []byte, leftOverGas uint64, err error) {
- fmt.Println("CallExpert")
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, gas, nil
}
diff --git a/eth/backend.go b/eth/backend.go
index ab43558..983909c 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -173,8 +173,6 @@ func New(ctx *node.ServiceContext, config *Config,
bcb: bcb,
}
- fmt.Println(eth.config.Genesis.GasLimit)
-
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
var dbVer = "<nil>"
if bcVersion != nil {
diff --git a/eth/gen_config.go b/eth/gen_config.go
index 617a885..d34f0b3 100644
--- a/eth/gen_config.go
+++ b/eth/gen_config.go
@@ -49,6 +49,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCGasCap *big.Int `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
+ OverrideIstanbul *big.Int
+ ManualCanonical bool
}
var enc Config
enc.Genesis = c.Genesis
@@ -82,6 +84,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCGasCap = c.RPCGasCap
enc.Checkpoint = c.Checkpoint
enc.CheckpointOracle = c.CheckpointOracle
+ enc.OverrideIstanbul = c.OverrideIstanbul
+ enc.ManualCanonical = c.ManualCanonical
return &enc, nil
}
@@ -119,6 +123,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCGasCap *big.Int `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
+ OverrideIstanbul *big.Int
+ ManualCanonical *bool
}
var dec Config
if err := unmarshal(&dec); err != nil {
@@ -217,5 +223,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.CheckpointOracle != nil {
c.CheckpointOracle = dec.CheckpointOracle
}
+ if dec.OverrideIstanbul != nil {
+ c.OverrideIstanbul = dec.OverrideIstanbul
+ }
+ if dec.ManualCanonical != nil {
+ c.ManualCanonical = *dec.ManualCanonical
+ }
return nil
}
diff --git a/eth/tracers/internal/tracers/assets.go b/eth/tracers/internal/tracers/assets.go
index d0a0bf7..b1930dc 100644
--- a/eth/tracers/internal/tracers/assets.go
+++ b/eth/tracers/internal/tracers/assets.go
@@ -3,7 +3,7 @@
// 4byte_tracer.js (2.933kB)
// bigram_tracer.js (1.712kB)
// call_tracer.js (8.643kB)
-// evmdis_tracer.js (4.194kB)
+// evmdis_tracer.js (4.195kB)
// noop_tracer.js (1.271kB)
// opcount_tracer.js (1.372kB)
// prestate_tracer.js (4.234kB)
@@ -28,7 +28,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
- return nil, fmt.Errorf("read %q: %v", name, err)
+ return nil, fmt.Errorf("read %q: %w", name, err)
}
var buf bytes.Buffer
@@ -36,7 +36,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close()
if err != nil {
- return nil, fmt.Errorf("read %q: %v", name, err)
+ return nil, fmt.Errorf("read %q: %w", name, err)
}
if clErr != nil {
return nil, err
@@ -137,7 +137,7 @@ func call_tracerJs() (*asset, error) {
return a, nil
}
-var _evmdis_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\xdf\x6f\xda\xca\x12\x7e\x86\xbf\x62\x94\x27\x50\x29\x60\x63\x08\x38\x27\x47\xe2\xa6\xf4\x1c\xae\xd2\x24\x02\x72\x8f\x2a\x94\x87\x05\xc6\xb0\xaa\xf1\x5a\xbb\x6b\x72\xb8\x55\xfe\xf7\xab\xd9\x59\x03\xf9\x75\xdb\x4a\xa7\x0f\x3b\xb5\x77\xbe\x6f\xbe\x9d\x19\xcf\x92\x56\x0b\xae\x54\xbe\xd7\x72\xbd\xb1\x10\xb6\x83\x73\x98\x6d\x10\xd6\xea\x23\xda\x0d\x6a\x2c\xb6\x30\x2c\xec\x46\x69\x53\x6d\xb5\x60\xb6\x91\x06\x12\x99\x22\x48\x03\xb9\xd0\x16\x54\x02\xf6\x85\x7f\x2a\x17\x5a\xe8\x7d\xb3\xda\x6a\x31\xe6\xcd\x6d\x62\x48\x34\x22\x18\x95\xd8\x47\xa1\x31\x86\xbd\x2a\x60\x29\x32\xd0\xb8\x92\xc6\x6a\xb9\x28\x2c\x82\xb4\x20\xb2\x55\x4b\x69\xd8\xaa\x95\x4c\xf6\x44\x29\x2d\x14\xd9\x0a\xb5\x0b\x6d\x51\x6f\x4d\xa9\xe3\x8f\x9b\x7b\xb8\x46\x63\x50\xc3\x1f\x98\xa1\x16\x29\xdc\x15\x8b\x54\x2e\xe1\x5a\x2e\x31\x33\x08\xc2\x40\x4e\x6f\xcc\x06\x57\xb0\x70\x74\x04\xfc\x4c\x52\xa6\x5e\x0a\x7c\x56\x45\xb6\x12\x56\xaa\xac\x01\x28\x49\x39\xec\x50\x1b\xa9\x32\xe8\x94\xa1\x3c\x61\x03\x94\x26\x92\x9a\xb0\x74\x00\x0d\x2a\x27\x5c\x1d\x44\xb6\x87\x54\xd8\x23\xf4\x27\x12\x72\x3c\xf7\x0a\x64\xe6\xc2\x6c\x54\x8e\x60\x37\xc2\xd2\xa9\x1f\x65\x9a\xc2\x02\xa1\x30\x98\x14\x69\x83\xd8\x16\x85\x85\xbf\xc6\xb3\x3f\x6f\xef\x67\x30\xbc\xf9\x0a\x7f\x0d\x27\x93\xe1\xcd\xec\xeb\x05\x3c\x4a\xbb\x51\x85\x05\xdc\x21\x53\xc9\x6d\x9e\x4a\x5c\xc1\xa3\xd0\x5a\x64\x76\x0f\x2a\x21\x86\x2f\xa3\xc9\xd5\x9f\xc3\x9b\xd9\xf0\x5f\xe3\xeb\xf1\xec\x2b\x28\x0d\x9f\xc7\xb3\x9b\xd1\x74\x0a\x9f\x6f\x27\x30\x84\xbb\xe1\x64\x36\xbe\xba\xbf\x1e\x4e\xe0\xee\x7e\x72\x77\x3b\x1d\x35\x61\x8a\xa4\x0a\x09\xff\xe3\x9c\x27\xae\x7a\x1a\x61\x85\x56\xc8\xd4\x94\x99\xf8\xaa\x0a\x30\x1b\x55\xa4\x2b\xd8\x88\x1d\x82\xc6\x25\xca\x1d\xae\x40\xc0\x52\xe5\xfb\x9f\x2e\x2a\x71\x89\x54\x65\x6b\x77\xe6\x77\x1b\x12\xc6\x09\x64\xca\x36\xc0\x20\xc2\x6f\x1b\x6b\xf3\xb8\xd5\x7a\x7c\x7c\x6c\xae\xb3\xa2\xa9\xf4\xba\x95\x32\x9d\x69\xfd\xde\xac\x12\x27\xee\xb6\x2b\x69\x66\x5a\x2c\x51\x83\x46\x5b\xe8\xcc\x80\x29\x92\x84\xfc\x2c\xc8\x2c\x51\x7a\xeb\xda\x04\x12\xad\xb6\x20\xc0\x92\x2f\x58\x05\x39\x6a\xda\xf4\x14\x1f\x8d\xdd\xa7\x4e\xe6\x4a\x1a\x61\x0c\x6e\x17\xe9\xbe\x59\xfd\x5e\xad\x18\x2b\x96\xdf\x62\x98\x7f\x57\xb9\x89\x61\xfe\xf0\xf4\xd0\xa8\x56\x2b\x59\x5e\x98\x0d\x9a\x18\xbe\xb7\x63\x68\x37\x20\x88\x21\x68\x40\xe8\xd6\x8e\x5b\x23\xb7\x76\xdd\xda\x73\xeb\xb9\x5b\xfb\x6e\x1d\xb8\x35\x68\xb3\x61\x74\xc0\x6e\x01\xfb\x05\xec\x18\xb0\x67\xc8\x9e\xa1\x8f\xc3\x81\x42\x8e\x14\x72\xa8\x90\x63\x85\xcc\xd2\x61\x97\x88\x59\x22\x66\xe9\x32\x4b\x97\x59\xba\xec\xd2\x65\x96\xae\x17\xdc\x75\xe7\xe9\x32\x4b\xf7\x9c\x9f\x98\xa5\xcb\x2c\x3d\x3e\x72\x8f\x01\x3d\x7f\x44\x06\xf4\x58\x7c\x8f\x01\x3d\x06\xf4\x19\xd0\xe7\xb0\xfd\x90\x9f\x3a\x6c\x98\xa5\xcf\x61\xfb\x3d\x36\x1c\xb6\xcf\x2c\x7d\x66\x19\xb0\xf8\x41\xe0\xf6\x06\x1c\x6f\xc0\xf1\x06\x3e\xab\x65\x5a\x7d\x5e\xdb\x3e\xb1\xed\xd0\xdb\x8e\xb7\x91\xb7\x5d\x6f\x7d\xe6\xdb\x3e\xf5\x6d\x9f\xfb\xb6\xe7\x3b\xd4\xc9\xf3\x05\x9e\x2f\xf0\x7c\x81\xe7\x0b\x3c\x5f\x59\xc9\xb2\x94\x65\x2d\x7d\x31\x03\x5f\xcd\xc0\x97\x33\xf0\xf5\x0c\x7c\x41\x03\x5f\xd1\xc0\x97\x34\xf0\x35\x0d\x42\xcf\x17\xf6\x63\x08\xc9\x0e\x62\xe8\x34\x20\xe8\xb4\x63\x88\xc8\x06\x31\x74\xc9\x86\x31\xf4\xc8\x76\x62\x38\x27\x1b\xc5\xd0\x27\xdb\x8d\x61\x40\x96\xf8\xa8\x6b\x3b\x44\x48\x8c\x1d\x52\x48\x94\x1d\x92\x48\x9c\x11\x69\x24\xd2\x88\x44\x12\x6b\x44\x2a\x89\x36\x22\x99\xc4\x1b\x45\xac\x23\xea\xb2\x8e\xa8\xc7\x3a\xa2\x73\xd6\x41\xdd\xe7\x00\x03\xd6\x41\xfd\x47\x3a\xa8\x01\x49\x87\xeb\x40\xd2\xe1\x7a\x90\x74\xb8\x2e\x24\x4a\xea\x43\xa7\xc3\x75\x22\x91\x52\x2f\x3a\x1d\xae\x1b\x89\xd6\xf5\x23\xf1\xfa\x8e\x0c\x7a\x81\xb7\xa1\xb7\x1d\x6f\x23\x67\xc3\xc8\x7f\x45\x91\xff\x8c\x22\xff\x1d\x45\x1d\xbf\xef\xfd\xdc\x47\xf0\x44\xdf\x79\xab\x05\x1a\x4d\x91\x5a\x1a\xfe\x32\xdb\xa9\x6f\x34\x9e\x37\x98\x81\x48\x53\x37\xc7\x54\xbe\x54\x2b\x34\x3c\x1f\x17\x88\x19\x48\x8b\x5a\xd0\x05\xa1\x76\xa8\xe9\x6e\x2c\x27\x93\xa3\x23\x4c\x22\x33\x91\x96\xc4\x7e\x86\xd2\x60\x92\xd9\xba\x59\xad\xf0\xfb\x18\x92\x22\x5b\xd2\xe8\xaa\xd5\xe1\xbb\xa7\x00\xbb\x91\xa6\xe9\x46\xd2\xbc\xfd\xd0\x54\xb9\xb9\x80\x52\x67\x22\xde\x92\x49\xd4\x62\x69\x0b\x91\x02\xfe\x8d\xcb\xc2\xcd\x42\x95\x80\xc8\xbc\x72\x48\x78\xe0\x57\x1c\xfe\x24\x6a\xaa\xd6\x0d\x58\x2d\x28\x78\x19\xc2\x58\xcc\x4f\x23\xd0\xb5\x81\x3b\xd4\xfb\x92\xcb\x5d\x83\x14\xf2\x3f\x5f\x7c\x38\x24\x6a\xc2\xbd\xc9\x5c\xad\x54\x76\x42\x43\xa2\xc5\x16\xe1\xf2\xf4\x74\xc7\xff\x36\x53\xcc\xd6\x76\x03\x1f\x21\x78\xb8\xa8\x7a\x04\x6a\xad\x34\x5c\x42\xaa\xd6\xcd\x35\xda\x11\x3d\xd6\xea\x17\xd5\x4a\x45\x26\x50\x73\xbb\x4c\x5f\x71\xdc\xf3\x33\xf7\xea\xec\x01\x2e\x19\x4a\x9e\x4f\x80\xa9\x41\x20\x80\xa7\xf9\x84\xb9\xdd\xd4\xea\x70\x79\x2a\xc5\xc7\xf7\x74\x2a\xa7\x4b\x05\x2e\xf9\xa9\xa2\xf2\x18\xe8\x1f\x11\xa8\xbc\x69\xd5\x4d\xb1\x5d\xa0\xae\xd5\x1b\x6e\x7b\x45\x84\x10\xc3\x73\x7e\xde\x2b\xcb\x3c\x7f\x70\xcf\x4f\x24\xc9\xa9\x77\x8a\xa9\xb6\xe5\xc9\x7f\x87\xb6\x8f\xee\xce\x9e\x6b\xdc\xa9\x1c\x2e\xe1\xe0\x38\x7f\x05\xe1\x64\x11\x22\x51\xba\x46\x28\x09\x97\xd0\xbe\x00\x09\xbf\xf1\xd9\xfc\x0d\x36\x67\xb6\xa6\xca\x1f\x2e\x40\x7e\xf8\x50\x77\xa0\x8a\x7f\xcb\x1a\x9b\xe4\xea\x72\xc4\x09\xc9\x11\xbf\xd5\x64\xbd\x69\xd5\xd4\x6a\x99\xad\x6b\x41\xaf\xee\x72\x5f\x79\xa2\xc5\x3c\x4a\xbb\x64\x7f\x97\x12\xef\x54\xf7\x67\x58\x0a\x83\x70\x76\x35\xbc\xbe\x3e\x8b\xe1\xf8\x70\x75\xfb\x69\x74\x16\x1f\x0e\x29\x33\x63\xe9\xe7\x2b\x97\xf8\x24\x6e\xa7\xde\xdc\x89\xb4\xc0\xdb\x84\xeb\x7d\x70\x97\xff\xc5\xd7\xde\xd1\x2b\x6f\x2e\xe0\xfc\x6c\x2d\x8c\x6b\x87\x17\x80\xf6\xbb\x00\xab\xde\xf2\x0f\x9e\xa7\xe1\x39\xc4\x31\xbd\x85\x0a\x4f\x50\x2f\x30\x32\xcb\x0b\x7b\xc0\x6c\x71\xab\xf4\xbe\x69\xe8\x87\x4f\xcd\xe7\xa4\x71\x48\xce\x07\x7f\xee\x17\x14\xc7\x5e\xcf\x8a\x34\x7d\xbe\xc7\x73\xe4\x9d\x4d\x95\x73\x4e\xe6\xbe\x77\x4e\x3e\x02\xd7\x02\xec\xe7\xa3\x2d\x34\x8a\x6f\x17\xc7\x8a\x7e\x1a\x5d\x8f\xfe\x18\xce\x46\xcf\x2a\x3b\x9d\x0d\x67\xe3\x2b\x7e\xf5\xe3\xda\x86\xbf\x54\xdb\xd7\x9d\x70\x3c\x87\x3b\x06\xbc\x6a\xc1\xb7\x5b\xe0\x97\x7b\xe0\x97\x9a\xe0\x58\xd0\x7f\xa2\xa2\xff\xbf\xa4\xff\x74\x4d\x27\xa3\xd9\xfd\xe4\xe6\xa4\x74\xf4\xe7\xca\x4f\x7c\x33\xde\xf5\xed\xba\x05\xaf\xdc\x79\x7c\xf9\x2b\xee\x8d\xc6\x57\x85\x6d\xb8\xd0\x1f\x4a\xd6\x77\xf4\x4e\x67\xb7\x77\xc7\xde\xbb\x1f\x5f\x8d\x0f\x43\xe5\x47\x31\xda\x0d\x68\xbf\xc3\xfa\xef\xfb\x2f\x77\x9f\x46\xd3\x99\x67\x2a\x33\x9b\x2f\x0f\x9f\xe9\x1a\xed\xdd\x55\xed\x64\x06\xca\xa4\x9c\x7f\xd2\xdc\x51\x9a\xcb\xe9\x77\x40\xa7\x98\x1d\xe0\xcf\x6e\x0e\xf8\x08\xed\xbf\xbb\x78\xe4\x3a\x0e\xf7\x97\x05\xf3\x37\x98\x23\x3e\xd6\xf5\xd9\x45\x7a\x3c\xdd\xf3\x3b\x88\xf1\xd5\xca\x53\xf5\xa9\xfa\xbf\x00\x00\x00\xff\xff\x51\x4b\xdc\x7e\x62\x10\x00\x00")
+var _evmdis_tracerJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x57\xdf\x6f\xda\xca\x12\x7e\x86\xbf\x62\x94\x27\x50\x29\x60\x63\x08\x38\x27\x47\xe2\xa6\xf4\x1c\xae\xd2\x24\x02\x72\x8f\x2a\x94\x87\x05\xc6\xb0\xaa\xf1\x5a\xbb\x6b\x72\xb8\x55\xfe\xf7\xab\xd9\x59\x03\xf9\x75\xdb\x4a\xa7\x0f\x3b\xb5\x77\xbe\x6f\xbe\x9d\x19\xcf\x92\x56\x0b\xae\x54\xbe\xd7\x72\xbd\xb1\x10\xb6\x83\x73\x98\x6d\x10\xd6\xea\x23\xda\x0d\x6a\x2c\xb6\x30\x2c\xec\x46\x69\x53\x6d\xb5\x60\xb6\x91\x06\x12\x99\x22\x48\x03\xb9\xd0\x16\x54\x02\xf6\x85\x7f\x2a\x17\x5a\xe8\x7d\xb3\xda\x6a\x31\xe6\xcd\x6d\x62\x48\x34\x22\x18\x95\xd8\x47\xa1\x31\x86\xbd\x2a\x60\x29\x32\xd0\xb8\x92\xc6\x6a\xb9\x28\x2c\x82\xb4\x20\xb2\x55\x4b\x69\xd8\xaa\x95\x4c\xf6\x44\x29\x2d\x14\xd9\x0a\xb5\x0b\x6d\x51\x6f\x4d\xa9\xe3\x8f\x9b\x7b\xb8\x46\x63\x50\xc3\x1f\x98\xa1\x16\x29\xdc\x15\x8b\x54\x2e\xe1\x5a\x2e\x31\x33\x08\xc2\x40\x4e\x6f\xcc\x06\x57\xb0\x70\x74\x04\xfc\x4c\x52\xa6\x5e\x0a\x7c\x56\x45\xb6\x12\x56\xaa\xac\x01\x28\x49\x39\xec\x50\x1b\xa9\x32\xe8\x94\xa1\x3c\x61\x03\x94\x26\x92\x9a\xb0\x74\x00\x0d\x2a\x27\x5c\x1d\x44\xb6\x87\x54\xd8\x23\xf4\x27\x12\x72\x3c\xf7\x0a\x64\xe6\xc2\x6c\x54\x8e\x60\x37\xc2\xd2\xa9\x1f\x65\x9a\xc2\x02\xa1\x30\x98\x14\x69\x83\xd8\x16\x85\x85\xbf\xc6\xb3\x3f\x6f\xef\x67\x30\xbc\xf9\x0a\x7f\x0d\x27\x93\xe1\xcd\xec\xeb\x05\x3c\x4a\xbb\x51\x85\x05\xdc\x21\x53\xc9\x6d\x9e\x4a\x5c\xc1\xa3\xd0\x5a\x64\x76\x0f\x2a\x21\x86\x2f\xa3\xc9\xd5\x9f\xc3\x9b\xd9\xf0\x5f\xe3\xeb\xf1\xec\x2b\x28\x0d\x9f\xc7\xb3\x9b\xd1\x74\x0a\x9f\x6f\x27\x30\x84\xbb\xe1\x64\x36\xbe\xba\xbf\x1e\x4e\xe0\xee\x7e\x72\x77\x3b\x1d\x35\x61\x8a\xa4\x0a\x09\xff\xe3\x9c\x27\xae\x7a\x1a\x61\x85\x56\xc8\xd4\x94\x99\xf8\xaa\x0a\x30\x1b\x55\xa4\x2b\xd8\x88\x1d\x82\xc6\x25\xca\x1d\xae\x40\xc0\x52\xe5\xfb\x9f\x2e\x2a\x71\x89\x54\x65\x6b\x77\xe6\x77\x1b\x12\xc6\x09\x64\xca\x36\xc0\x20\xc2\x6f\x1b\x6b\xf3\xb8\xd5\x7a\x7c\x7c\x6c\xae\xb3\xa2\xa9\xf4\xba\x95\x32\x9d\x69\xfd\xde\xac\x12\x27\xee\xb6\x2b\x69\x66\x5a\x2c\x51\x83\x46\x5b\xe8\xcc\x80\x29\x92\x44\x2e\x25\x66\x16\x64\x96\x28\xbd\x75\x7d\x02\x89\x56\x5b\x10\x60\xc9\x19\xac\x82\x1c\x35\x6d\x7a\x8e\x8f\xc6\xee\x53\xa7\x73\x25\x8d\x30\x06\xb7\x8b\x74\xdf\xac\x7e\xaf\x56\x8c\x15\xcb\x6f\x31\xcc\xbf\xab\xdc\xc4\x30\x7f\x78\x7a\x68\x54\xab\x95\x2c\x2f\xcc\x06\x4d\x0c\xdf\xdb\x31\xb4\x1b\x10\xc4\x10\x34\x20\x74\x6b\xc7\xad\x91\x5b\xbb\x6e\xed\xb9\xf5\xdc\xad\x7d\xb7\x0e\xdc\x1a\xb4\xd9\x30\x3a\x60\xb7\x80\xfd\x02\x76\x0c\xd8\x33\x64\xcf\xd0\xc7\xe1\x40\x21\x47\x0a\x39\x54\xc8\xb1\x42\x66\xe9\xb0\x4b\xc4\x2c\x11\xb3\x74\x99\xa5\xcb\x2c\x5d\x76\xe9\x32\x4b\xd7\x0b\xee\xba\xf3\x74\x99\xa5\x7b\xce\x4f\xcc\xd2\x65\x96\x1e\x1f\xb9\xc7\x80\x9e\x3f\x22\x03\x7a\x2c\xbe\xc7\x80\x1e\x03\xfa\x0c\xe8\x73\xd8\x7e\xc8\x4f\x1d\x36\xcc\xd2\xe7\xb0\xfd\x1e\x1b\x0e\xdb\x67\x96\x3e\xb3\x0c\x58\xfc\x20\x70\x7b\x03\x8e\x37\xe0\x78\x03\x9f\xd5\x32\xad\x3e\xaf\x6d\x9f\xd8\x76\xe8\x6d\xc7\xdb\xc8\xdb\xae\xb7\x3e\xf3\x6d\x9f\xfa\xb6\xcf\x7d\xdb\xf3\x1d\xea\xe4\xf9\x02\xcf\x17\x78\xbe\xc0\xf3\x05\x9e\xaf\xac\x64\x59\xca\xb2\x96\xbe\x98\x81\xaf\x66\xe0\xcb\x19\xf8\x7a\x06\xbe\xa0\x81\xaf\x68\xe0\x4b\x1a\xf8\x9a\x06\xa1\xe7\x0b\xfb\x31\x84\x64\x07\x31\x74\x1a\x10\x74\xda\x31\x44\x64\x83\x18\xba\x64\xc3\x18\x7a\x64\x3b\x31\x9c\x93\x8d\x62\xe8\x93\xed\xc6\x30\x20\x4b\x7c\xd4\xb5\x1d\x22\x24\xc6\x0e\x29\x24\xca\x0e\x49\x24\xce\x88\x34\x12\x69\x44\x22\x89\x35\x22\x95\x44\x1b\x91\x4c\xe2\x8d\x22\xd6\x11\x75\x59\x47\xd4\x63\x1d\xd1\x39\xeb\xa0\xee\x73\x80\x01\xeb\xa0\xfe\x23\x1d\xd4\x80\xa4\xc3\x75\x20\xe9\x70\x3d\x48\x3a\x5c\x17\x12\x25\xf5\xa1\xd3\xe1\x3a\x91\x48\xa9\x17\x9d\x0e\xd7\x8d\x44\xeb\xfa\x91\x78\x7d\x47\x06\xbd\xc0\xdb\xd0\xdb\x8e\xb7\x91\xb3\x61\xe4\xbf\xa2\xc8\x7f\x46\x91\xff\x8e\xa2\x8e\xdf\xf7\x7e\xee\x23\x78\xa2\xef\xbc\xd5\x02\x8d\xa6\x48\x2d\x4d\x7f\x99\xed\xd4\x37\x9a\xcf\x1b\xcc\x40\xa4\xa9\x1b\x64\x2a\x5f\xaa\x15\x1a\x1e\x90\x0b\xc4\x0c\xa4\x45\x2d\xe8\x86\x50\x3b\xd4\x74\x39\x96\xa3\xc9\xd1\x11\x26\x91\x99\x48\x4b\x62\x3f\x44\x69\x30\xc9\x6c\xdd\xac\x56\xf8\x7d\x0c\x49\x91\x2d\x69\x74\xd5\xea\xf0\xdd\x53\x80\xdd\x48\xd3\x74\x23\x69\xde\x7e\x68\xaa\xdc\x5c\x40\xa9\x33\x11\x6f\xc9\x24\x6a\xb1\xb4\x85\x48\x01\xff\xc6\x65\xe1\x66\xa1\x4a\x40\x64\x5e\x39\x24\x3c\xf1\x2b\x0e\x7f\x12\x35\x55\xeb\x06\xac\x16\x14\xbc\x0c\x61\x2c\xe6\xa7\x11\xe8\xde\xc0\x1d\xea\x7d\xc9\xe5\xee\x41\x0a\xf9\x9f\x2f\x3e\x1c\x12\x35\xe1\xde\x64\xae\x56\x2a\x3b\xa1\x21\xd1\x62\x8b\x70\x79\x7a\xba\xe3\x7f\x9b\x29\x66\x6b\xbb\x81\x8f\x10\x3c\x5c\x54\x3d\x02\xb5\x56\x1a\x2e\x21\x55\xeb\xe6\x1a\xed\x88\x1e\x6b\xf5\x8b\x6a\xa5\x22\x13\xa8\xb9\x5d\xa6\xaf\x38\xee\xf9\x99\x7b\x75\xf6\x00\x97\x0c\x25\xcf\x27\xc0\xd4\x20\x10\xc0\xd3\x7c\xc2\xdc\x6e\x6a\x75\xb8\x3c\x95\xe2\xe3\x7b\x3a\x95\xd3\xa5\x02\x97\xfc\x54\x51\x79\x0c\xf4\x8f\x08\x54\xde\xb4\xea\xa6\xd8\x2e\x50\xd7\xea\x0d\xb7\xbd\x22\x42\x88\xe1\x39\x3f\xef\x95\x65\x9e\x3f\xb8\xe7\x27\x92\xe4\xd4\x3b\xc5\x54\xdb\xf2\xe4\xbf\x43\xdb\x47\x77\x67\xcf\x35\xee\x54\x0e\x97\x70\x70\x9c\xbf\x82\x70\xb2\x08\x91\x28\x5d\x23\x94\x84\x4b\x68\x5f\x80\x84\xdf\xf8\x6c\xfe\x06\x9b\x33\x5b\x53\xe5\x0f\x17\x20\x3f\x7c\xa8\x3b\x50\xc5\xbf\x65\x8d\x4d\x72\x75\x39\xe2\x84\xe4\x88\xdf\x6a\xb2\xde\xb4\x6a\x6a\xb5\xcc\xd6\xb5\xa0\x57\x77\xb9\xaf\x3c\xd1\x62\x1e\xa5\x5d\xb2\xbf\x4b\x89\x77\xaa\xfb\x33\x2c\x85\x41\x38\xbb\x1a\x5e\x5f\x9f\xc5\x70\x7c\xb8\xba\xfd\x34\x3a\x8b\x0f\x87\x94\x99\xb1\xf4\xfb\x95\x4b\x7c\x12\xb7\x53\x6f\xee\x44\x5a\xe0\x6d\xc2\xf5\x3e\xb8\xcb\xff\xe2\x6b\xef\xe8\x95\x37\x17\x70\x7e\xb6\x16\xc6\xb5\xc3\x0b\x40\xfb\x5d\x80\x55\x6f\xf9\x07\xcf\xd3\xf0\x1c\xe2\x98\xde\x42\x85\x27\xa8\x17\x18\x99\xe5\x85\x3d\x60\xb6\xb8\x55\x7a\xdf\x34\xf4\xcb\xa7\xe6\x73\xd2\x38\x24\xe7\x83\x3f\xf7\x0b\x8a\x63\xaf\x67\x45\x9a\x3e\xdf\xe3\x39\xf2\xce\xa6\xca\x39\x27\x73\xdf\x3b\x27\x1f\x81\x6b\x01\xf6\xf3\xd1\x16\x1a\xc5\xb7\x8b\x63\x45\x3f\x8d\xae\x47\x7f\x0c\x67\xa3\x67\x95\x9d\xce\x86\xb3\xf1\x15\xbf\xfa\x71\x6d\xc3\x5f\xaa\xed\xeb\x4e\x38\x9e\xc3\x1d\x03\x5e\xb5\xe0\xdb\x2d\xf0\xcb\x3d\xf0\x4b\x4d\x70\x2c\xe8\x3f\x51\xd1\xff\x5f\xd2\x7f\xba\xa6\x93\xd1\xec\x7e\x72\x73\x52\x3a\xfa\x7b\xe5\x27\xbe\x19\xef\xfa\x76\xdd\x82\x57\xee\x3c\xbe\xfc\x15\xf7\x46\xe3\xab\xc2\x36\x5c\xe8\x0f\x25\xeb\x3b\x7a\xa7\xb3\xdb\xbb\x63\xef\xdd\x8f\xaf\xc6\x87\xa1\xf2\xa3\x18\xed\x06\xb4\xdf\x61\xfd\xf7\xfd\x97\xbb\x4f\xa3\xe9\xcc\x33\x95\x99\xcd\x97\x87\xcf\x74\x8d\xf6\xee\xaa\x76\x32\x03\x65\x52\xce\x3f\x69\xee\x28\xcd\xe5\xf4\x3b\xa0\x53\xcc\x0e\xf0\x67\x37\x07\x7c\x84\xf6\xdf\x5d\x3c\x72\x1d\x87\xfb\xcb\x82\xf9\x1b\xcc\x11\x1f\xeb\xfa\xec\x22\x3d\x9e\xee\xf9\x1d\xc4\xf8\x6a\xe5\xa9\xfa\x54\xfd\x5f\x00\x00\x00\xff\xff\xdf\x2f\xd9\xfa\x63\x10\x00\x00")
func evmdis_tracerJsBytes() ([]byte, error) {
return bindataRead(
@@ -153,7 +153,7 @@ func evmdis_tracerJs() (*asset, error) {
}
info := bindataFileInfo{name: "evmdis_tracer.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
- a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd5, 0xe8, 0x96, 0xa1, 0x8b, 0xc, 0x68, 0x3c, 0xe8, 0x5d, 0x7e, 0xf0, 0xab, 0xfe, 0xec, 0xd1, 0xb, 0x3d, 0xfc, 0xc7, 0xac, 0xb5, 0xa, 0x41, 0x55, 0x0, 0x3a, 0x60, 0xa7, 0x8e, 0x46, 0x93}}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb5, 0xc8, 0x73, 0x8e, 0xfb, 0x1f, 0x84, 0x7d, 0x37, 0xd9, 0x26, 0x24, 0x37, 0xb8, 0x65, 0xb1, 0xed, 0xa0, 0x76, 0x9a, 0xf0, 0x8e, 0x3a, 0x9b, 0x20, 0x93, 0x27, 0x26, 0x2e, 0xc9, 0x9b, 0xde}}
return a, nil
}
@@ -348,25 +348,20 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
- "4byte_tracer.js": _4byte_tracerJs,
-
- "bigram_tracer.js": bigram_tracerJs,
-
- "call_tracer.js": call_tracerJs,
-
- "evmdis_tracer.js": evmdis_tracerJs,
-
- "noop_tracer.js": noop_tracerJs,
-
- "opcount_tracer.js": opcount_tracerJs,
-
+ "4byte_tracer.js": _4byte_tracerJs,
+ "bigram_tracer.js": bigram_tracerJs,
+ "call_tracer.js": call_tracerJs,
+ "evmdis_tracer.js": evmdis_tracerJs,
+ "noop_tracer.js": noop_tracerJs,
+ "opcount_tracer.js": opcount_tracerJs,
"prestate_tracer.js": prestate_tracerJs,
-
- "trigram_tracer.js": trigram_tracerJs,
-
- "unigram_tracer.js": unigram_tracerJs,
+ "trigram_tracer.js": trigram_tracerJs,
+ "unigram_tracer.js": unigram_tracerJs,
}
+// AssetDebug is true if the assets were built with the debug flag enabled.
+const AssetDebug = false
+
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
diff --git a/examples/chain/main.go b/examples/chain/main.go
index d474c2b..5edd055 100644
--- a/examples/chain/main.go
+++ b/examples/chain/main.go
@@ -7,10 +7,10 @@ import (
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/eth"
+ "github.com/ava-labs/coreth/params"
"github.com/ava-labs/go-ethereum/common"
"github.com/ava-labs/go-ethereum/common/hexutil"
"github.com/ava-labs/go-ethereum/log"
- "github.com/ava-labs/go-ethereum/params"
"github.com/ava-labs/go-ethereum/rlp"
"math/big"
"sync"
diff --git a/examples/counter/main.go b/examples/counter/main.go
index 48a0e6f..85aa9d1 100644
--- a/examples/counter/main.go
+++ b/examples/counter/main.go
@@ -9,11 +9,11 @@ import (
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/eth"
+ "github.com/ava-labs/coreth/params"
"github.com/ava-labs/go-ethereum/common"
"github.com/ava-labs/go-ethereum/common/compiler"
"github.com/ava-labs/go-ethereum/crypto"
"github.com/ava-labs/go-ethereum/log"
- "github.com/ava-labs/go-ethereum/params"
"go/build"
"math/big"
"os"
diff --git a/examples/multicoin/main.go b/examples/multicoin/main.go
new file mode 100644
index 0000000..3e42010
--- /dev/null
+++ b/examples/multicoin/main.go
@@ -0,0 +1,218 @@
+package main
+
+import (
+ "crypto/rand"
+ //"encoding/hex"
+ "encoding/json"
+ "fmt"
+ "github.com/ava-labs/coreth"
+ "github.com/ava-labs/coreth/core"
+ "github.com/ava-labs/coreth/eth"
+ //"github.com/ava-labs/coreth/accounts/abi"
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ava-labs/coreth/params"
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/compiler"
+ "github.com/ava-labs/go-ethereum/crypto"
+ "github.com/ava-labs/go-ethereum/log"
+ "go/build"
+ "math/big"
+ "os"
+ "os/signal"
+ "path/filepath"
+ //"strings"
+ "syscall"
+ "time"
+)
+
+var (
+ codeHex = "6101c7610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061004b5760003560e01c80631e01043914610050578063abb24ba014610092578063b6510bb3146100a9575b600080fd5b61007c6004803603602081101561006657600080fd5b8101908080359060200190929190505050610118565b6040518082815260200191505060405180910390f35b81801561009e57600080fd5b506100a761013b565b005b8180156100b557600080fd5b50610116600480360360808110156100cc57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061013e565b005b60003373ffffffffffffffffffffffffffffffffffffffff1682905d9050919050565b5c565b8373ffffffffffffffffffffffffffffffffffffffff1681836108fc8690811502906040516000604051808303818888878c8af69550505050505015801561018a573d6000803e3d6000fd5b505050505056fea26469706673582212204e4689067358d8e82903012dcaca0c004d36e39fc99360919fb824c4ce718bdd64736f6c634300060a0033"
+ codeABI = `[{"inputs":[{"internalType":"uint256","name":"coinid","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]`
+)
+
+func checkError(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
+
+func main() {
+ // configure the chain
+ config := eth.DefaultConfig
+ config.ManualCanonical = true
+ 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)
+ bob, _ := coreth.NewKey(rand.Reader)
+
+ g := new(core.Genesis)
+ b := `{"config":{"chainId":1,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x1000000000000000", "mcbalance": {"0x0000000000000000000000000000000000000000000000000000000000000000": 1000000000000000000}}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`
+ k := "0xabd71b35d559563fea757f0f5edbde286fb8c043105b15abb7cd57189306d7d1"
+ err := json.Unmarshal([]byte(b), g)
+ checkError(err)
+ config.Genesis = g
+ hk, _ := crypto.HexToECDSA(k[2:])
+ genKey = coreth.NewKeyFromECDSA(hk)
+ //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
+ gopath := os.Getenv("GOPATH")
+ if gopath == "" {
+ gopath = build.Default.GOPATH
+ }
+
+ // 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, nil, nil)
+ newTxPoolHeadChan := make(chan core.NewTxPoolHeadEvent, 1)
+ log.Info(chain.GetGenesisBlock().Hash().Hex())
+ firstBlock := false
+ var contractAddr common.Address
+ coin0 := common.HexToHash("0x0")
+ //var calls [][]byte
+ 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("genesis balance2 = %s", state.GetBalanceMultiCoin(genKey.Address, coin0)))
+ log.Info(fmt.Sprintf("contract balance = %s", state.GetBalance(contractAddr)))
+ log.Info(fmt.Sprintf("bob's balance = %s", state.GetBalance(bob.Address)))
+ log.Info(fmt.Sprintf("bob's balance2 = %s", state.GetBalanceMultiCoin(bob.Address, coin0)))
+ 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(fmt.Sprintf("# receipts is %d != 1", len(receipts)))
+ }
+ 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()))
+ //var call []byte
+ //if len(calls) > 0 {
+ // call = calls[0]
+ // calls = calls[1:]
+ //} else {
+ // call = nil
+ //}
+ //state, _ := chain.CurrentState()
+ //call := common.Hex2Bytes("1003e2d20000000000000000000000000000000000000000000000000000000000000001")
+ //log.Info(fmt.Sprintf("code = %s", hex.EncodeToString(state.GetCode(contractAddr))))
+ go func() {
+ tx := types.NewTransaction(nonce, bob.Address, big.NewInt(300000000000000000), uint64(gasLimit), gasPrice, nil)
+ signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey)
+ checkError(err)
+ chain.AddRemoteTxs([]*types.Transaction{signedTx})
+ nonce++
+ time.Sleep(20 * time.Millisecond)
+
+ // self-loop tx to enable MC
+ tx = types.NewTransaction(0, bob.Address, big.NewInt(1), uint64(gasLimit), gasPrice, nil)
+ tx.SetMultiCoinValue(&coin0, big.NewInt(0))
+ signedTx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), bob.PrivateKey)
+ checkError(err)
+ chain.AddRemoteTxs([]*types.Transaction{signedTx})
+ time.Sleep(20 * time.Millisecond)
+
+ for i := 0; i < 10; i++ {
+ tx := types.NewTransaction(nonce, bob.Address, big.NewInt(10000000000000000), uint64(gasLimit), gasPrice, nil)
+ tx.SetMultiCoinValue(&coin0, big.NewInt(100000000000000000))
+ signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey)
+ checkError(err)
+ chain.AddRemoteTxs([]*types.Transaction{signedTx})
+ nonce++
+ }
+ }()
+ }
+ return false
+ }
+ chain.SetOnHeaderNew(func(header *types.Header) {
+ hid := make([]byte, 32)
+ _, err := rand.Read(hid)
+ if err != nil {
+ panic("cannot generate hid")
+ }
+ header.Extra = append(header.Extra, hid...)
+ })
+ chain.SetOnSealFinish(func(block *types.Block) error {
+ blockCount++
+ if postGen(block) {
+ return nil
+ }
+ go func() {
+ <-newTxPoolHeadChan
+ time.Sleep(10 * time.Millisecond)
+ chain.GenBlock()
+ }()
+ return nil
+ })
+
+ // start the chain
+ chain.GetTxPool().SubscribeNewHeadEvent(newTxPoolHeadChan)
+ chain.Start()
+
+ //code := common.Hex2Bytes(codeHex)
+ counterSrc, err := filepath.Abs(gopath + "/src/github.com/ava-labs/coreth/examples/counter/counter.sol")
+ checkError(err)
+ contracts, err := compiler.CompileSolidity("", counterSrc)
+ checkError(err)
+ contract, _ := contracts[fmt.Sprintf("%s:%s", counterSrc, "Counter")]
+ code := common.Hex2Bytes(contract.Code[2:])
+
+ //abi, err := abi.JSON(strings.NewReader(codeABI))
+ //cc, err := abi.Pack("getBalance", big.NewInt(0))
+ //checkError(err)
+ //calls = append(calls, cc)
+ 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/plugin/evm/static_service_test.go b/plugin/evm/static_service_test.go
deleted file mode 100644
index c492798..0000000
--- a/plugin/evm/static_service_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package evm
-
-import (
- "math/big"
- "testing"
-
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/params"
-
- "github.com/ava-labs/coreth/core"
-)
-
-func TestBuildGenesis(t *testing.T) {
- expected := "3wP629bGfSGj9trh1UNBp5qGRGCcma5d8ezLeSmd9hnUJjSMUJesHHoxbZNcVUC9CjH7PEGNA96htNTd1saZCMt1Mf1dZFG7JDhcYNok6RS4TZufejXdxbVVgquohSa7nCCcrXpiVeiRFwzLJAxyQbXzYRhaCRtcDDfCcqfaVdtkFsPbNeQ49pDTbEC5hVkmfopeQ2Zz8tAG5QXKBdbYBCukR3xNHJ4xDxeixmEwPr1odb42yQRYrL7xREKNn2LFoFwAWUjBTsCkf5GPNgY2GvvN9o8wFWXTroW5fp754DhpdxHYxkMTfuE9DGyNWHTyrEbrUHutUdsfitcSHVj5ctFtkN2wGCs3cyv1eRRNvFFMggWTbarjne6AYaeCrJ631qAu3CbrUtrTH5N2E6G2yQKX4sT4Sk3qWPJdsGXuT95iKKcgNn1u5QRHHw9DXXuGPpJjkcKQRGUCuqpXy61iF5RNPEwAwKDa8f2Y25WMmNgWynUuLj8iSAyePj7USPWk54QFUr86ApVzqAdzzdD1qSVScpmudGnGbz9UNXdzHqSot6XLrNTYsgkabiu6TGntFm7qywbCRmtNdBuT9aznGQdUVimjt5QzUz68HXhUxBzTkrz7yXfVGV5JcWxVHQXYS4oc41U5yu83mH3A7WBrZLVq6UyNrvQVbim5nDxeKKbALPxwzVwywjgY5cp39AvzGnY8CX2AtuBNnKmZaAvG8JWAkx3yxjnJrwWhLgpDQYcCvRp2jg1EPBqN8FKJxSPE6eedjDHDJfB57mNzyEtmg22BPnem3eLdiovX8awkhBUHdE7uPrapNSVprnS85u1saW2Kwza3FsS2jAM3LckGW8KdtfPTpHBTRKAUo49zZLuPsyGL5WduedGyAdaM3a2KPoyXuz4UbexTVUWFNypFvvgyoDS8FMxDCNoMMaD7y4yVnoDpSpVFEVZD6EuSGHe9U8Ew57xLPbjhepDx6"
-
- balance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16)
- if !success {
- t.Fatal("Failed to initialize balance")
- }
-
- args := core.Genesis{
- Config: &params.ChainConfig{
- ChainID: big.NewInt(43110),
- 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),
- },
- Nonce: 0,
- Timestamp: 0,
- ExtraData: []byte{},
- GasLimit: 100000000,
- Difficulty: big.NewInt(0),
- Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
- Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"),
- Alloc: core.GenesisAlloc{
- common.HexToAddress("751a0b96e1042bee789452ecb20253fba40dbe85"): core.GenesisAccount{
- Balance: balance,
- },
- },
- Number: 0,
- GasUsed: 0,
- ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
- }
-
- ss := StaticService{}
- result, err := ss.BuildGenesis(nil, &args)
- if err != nil {
- t.Fatal(err)
- }
-
- if result.String() != expected {
- t.Fatalf("StaticService.BuildGenesis:\nReturned: %s\nExpected: %s", result, expected)
- }
-}
diff --git a/plugin/evm/vm_genesis_parse_test.go b/plugin/evm/vm_genesis_parse_test.go
deleted file mode 100644
index 9a113fb..0000000
--- a/plugin/evm/vm_genesis_parse_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package evm
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/ava-labs/coreth/core"
-)
-
-func TestParseGenesis(t *testing.T) {
- genesis := []byte(`{"config":{"chainId":43110,"homesteadBlock":0,"daoForkBlock":0,"daoForkSupport":true,"eip150Block":0,"eip150Hash":"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0","eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x5f5e100","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"751a0b96e1042bee789452ecb20253fba40dbe85":{"balance":"0x33b2e3c9fd0804000000000"}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`)
-
- genesisBlock := new(core.Genesis)
- err := json.Unmarshal(genesis, genesisBlock)
- if err != nil {
- t.Fatal(err)
- }
-
- marshalledBytes, err := json.Marshal(genesisBlock)
- if err != nil {
- t.Fatal(err)
- }
-
- secondGenesisBlock := new(core.Genesis)
- err = json.Unmarshal(marshalledBytes, secondGenesisBlock)
- if err != nil {
- t.Fatal(err)
- }
-}
diff --git a/rpc/client_example_test.go b/rpc/client_example_test.go
deleted file mode 100644
index 149de2c..0000000
--- a/rpc/client_example_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc_test
-
-import (
- "context"
- "fmt"
- "math/big"
- "time"
-
- "github.com/ava-labs/go-ethereum/rpc"
-)
-
-// In this example, our client wishes to track the latest 'block number'
-// known to the server. The server supports two methods:
-//
-// eth_getBlockByNumber("latest", {})
-// returns the latest block object.
-//
-// eth_subscribe("newBlocks")
-// creates a subscription which fires block objects when new blocks arrive.
-
-type Block struct {
- Number *big.Int
-}
-
-func ExampleClientSubscription() {
- // Connect the client.
- client, _ := rpc.Dial("ws://127.0.0.1:8485")
- subch := make(chan Block)
-
- // Ensure that subch receives the latest block.
- go func() {
- for i := 0; ; i++ {
- if i > 0 {
- time.Sleep(2 * time.Second)
- }
- subscribeBlocks(client, subch)
- }
- }()
-
- // Print events from the subscription as they arrive.
- for block := range subch {
- fmt.Println("latest block:", block.Number)
- }
-}
-
-// subscribeBlocks runs in its own goroutine and maintains
-// a subscription for new blocks.
-func subscribeBlocks(client *rpc.Client, subch chan Block) {
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Subscribe to new blocks.
- sub, err := client.EthSubscribe(ctx, subch, "newHeads")
- if err != nil {
- fmt.Println("subscribe error:", err)
- return
- }
-
- // The connection is established now.
- // Update the channel with the current block.
- var lastBlock Block
- if err := client.CallContext(ctx, &lastBlock, "eth_getBlockByNumber", "latest"); err != nil {
- fmt.Println("can't get latest block:", err)
- return
- }
- subch <- lastBlock
-
- // The subscription will deliver events to the channel. Wait for the
- // subscription to end for any reason, then loop around to re-establish
- // the connection.
- fmt.Println("connection lost: ", <-sub.Err())
-}
diff --git a/rpc/client_test.go b/rpc/client_test.go
deleted file mode 100644
index 79ea32e..0000000
--- a/rpc/client_test.go
+++ /dev/null
@@ -1,569 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "context"
- "fmt"
- "math/rand"
- "net"
- "net/http"
- "net/http/httptest"
- "os"
- "reflect"
- "runtime"
- "sync"
- "testing"
- "time"
-
- "github.com/davecgh/go-spew/spew"
- "github.com/ava-labs/go-ethereum/log"
-)
-
-func TestClientRequest(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- var resp Result
- if err := client.Call(&resp, "test_echo", "hello", 10, &Args{"world"}); err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(resp, Result{"hello", 10, &Args{"world"}}) {
- t.Errorf("incorrect result %#v", resp)
- }
-}
-
-func TestClientBatchRequest(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- batch := []BatchElem{
- {
- Method: "test_echo",
- Args: []interface{}{"hello", 10, &Args{"world"}},
- Result: new(Result),
- },
- {
- Method: "test_echo",
- Args: []interface{}{"hello2", 11, &Args{"world"}},
- Result: new(Result),
- },
- {
- Method: "no_such_method",
- Args: []interface{}{1, 2, 3},
- Result: new(int),
- },
- }
- if err := client.BatchCall(batch); err != nil {
- t.Fatal(err)
- }
- wantResult := []BatchElem{
- {
- Method: "test_echo",
- Args: []interface{}{"hello", 10, &Args{"world"}},
- Result: &Result{"hello", 10, &Args{"world"}},
- },
- {
- Method: "test_echo",
- Args: []interface{}{"hello2", 11, &Args{"world"}},
- Result: &Result{"hello2", 11, &Args{"world"}},
- },
- {
- Method: "no_such_method",
- Args: []interface{}{1, 2, 3},
- Result: new(int),
- Error: &jsonError{Code: -32601, Message: "the method no_such_method does not exist/is not available"},
- },
- }
- if !reflect.DeepEqual(batch, wantResult) {
- t.Errorf("batch results mismatch:\ngot %swant %s", spew.Sdump(batch), spew.Sdump(wantResult))
- }
-}
-
-func TestClientNotify(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- if err := client.Notify(context.Background(), "test_echo", "hello", 10, &Args{"world"}); err != nil {
- t.Fatal(err)
- }
-}
-
-// func TestClientCancelInproc(t *testing.T) { testClientCancel("inproc", t) }
-func TestClientCancelWebsocket(t *testing.T) { testClientCancel("ws", t) }
-func TestClientCancelHTTP(t *testing.T) { testClientCancel("http", t) }
-func TestClientCancelIPC(t *testing.T) { testClientCancel("ipc", t) }
-
-// This test checks that requests made through CallContext can be canceled by canceling
-// the context.
-func testClientCancel(transport string, t *testing.T) {
- // These tests take a lot of time, run them all at once.
- // You probably want to run with -parallel 1 or comment out
- // the call to t.Parallel if you enable the logging.
- t.Parallel()
-
- server := newTestServer()
- defer server.Stop()
-
- // What we want to achieve is that the context gets canceled
- // at various stages of request processing. The interesting cases
- // are:
- // - cancel during dial
- // - cancel while performing a HTTP request
- // - cancel while waiting for a response
- //
- // To trigger those, the times are chosen such that connections
- // are killed within the deadline for every other call (maxKillTimeout
- // is 2x maxCancelTimeout).
- //
- // Once a connection is dead, there is a fair chance it won't connect
- // successfully because the accept is delayed by 1s.
- maxContextCancelTimeout := 300 * time.Millisecond
- fl := &flakeyListener{
- maxAcceptDelay: 1 * time.Second,
- maxKillTimeout: 600 * time.Millisecond,
- }
-
- var client *Client
- switch transport {
- case "ws", "http":
- c, hs := httpTestClient(server, transport, fl)
- defer hs.Close()
- client = c
- case "ipc":
- c, l := ipcTestClient(server, fl)
- defer l.Close()
- client = c
- default:
- panic("unknown transport: " + transport)
- }
-
- // The actual test starts here.
- var (
- wg sync.WaitGroup
- nreqs = 10
- ncallers = 6
- )
- caller := func(index int) {
- defer wg.Done()
- for i := 0; i < nreqs; i++ {
- var (
- ctx context.Context
- cancel func()
- timeout = time.Duration(rand.Int63n(int64(maxContextCancelTimeout)))
- )
- if index < ncallers/2 {
- // For half of the callers, create a context without deadline
- // and cancel it later.
- ctx, cancel = context.WithCancel(context.Background())
- time.AfterFunc(timeout, cancel)
- } else {
- // For the other half, create a context with a deadline instead. This is
- // different because the context deadline is used to set the socket write
- // deadline.
- ctx, cancel = context.WithTimeout(context.Background(), timeout)
- }
- // Now perform a call with the context.
- // The key thing here is that no call will ever complete successfully.
- sleepTime := maxContextCancelTimeout + 20*time.Millisecond
- err := client.CallContext(ctx, nil, "test_sleep", sleepTime)
- if err != nil {
- log.Debug(fmt.Sprint("got expected error:", err))
- } else {
- t.Errorf("no error for call with %v wait time", timeout)
- }
- cancel()
- }
- }
- wg.Add(ncallers)
- for i := 0; i < ncallers; i++ {
- go caller(i)
- }
- wg.Wait()
-}
-
-func TestClientSubscribeInvalidArg(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- check := func(shouldPanic bool, arg interface{}) {
- defer func() {
- err := recover()
- if shouldPanic && err == nil {
- t.Errorf("EthSubscribe should've panicked for %#v", arg)
- }
- if !shouldPanic && err != nil {
- t.Errorf("EthSubscribe shouldn't have panicked for %#v", arg)
- buf := make([]byte, 1024*1024)
- buf = buf[:runtime.Stack(buf, false)]
- t.Error(err)
- t.Error(string(buf))
- }
- }()
- client.EthSubscribe(context.Background(), arg, "foo_bar")
- }
- check(true, nil)
- check(true, 1)
- check(true, (chan int)(nil))
- check(true, make(<-chan int))
- check(false, make(chan int))
- check(false, make(chan<- int))
-}
-
-func TestClientSubscribe(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- nc := make(chan int)
- count := 10
- sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", count, 0)
- if err != nil {
- t.Fatal("can't subscribe:", err)
- }
- for i := 0; i < count; i++ {
- if val := <-nc; val != i {
- t.Fatalf("value mismatch: got %d, want %d", val, i)
- }
- }
-
- sub.Unsubscribe()
- select {
- case v := <-nc:
- t.Fatal("received value after unsubscribe:", v)
- case err := <-sub.Err():
- if err != nil {
- t.Fatalf("Err returned a non-nil error after explicit unsubscribe: %q", err)
- }
- case <-time.After(1 * time.Second):
- t.Fatalf("subscription not closed within 1s after unsubscribe")
- }
-}
-
-// In this test, the connection drops while Subscribe is waiting for a response.
-func TestClientSubscribeClose(t *testing.T) {
- server := newTestServer()
- service := &notificationTestService{
- gotHangSubscriptionReq: make(chan struct{}),
- unblockHangSubscription: make(chan struct{}),
- }
- if err := server.RegisterName("nftest2", service); err != nil {
- t.Fatal(err)
- }
-
- defer server.Stop()
- client := DialInProc(server)
- defer client.Close()
-
- var (
- nc = make(chan int)
- errc = make(chan error)
- sub *ClientSubscription
- err error
- )
- go func() {
- sub, err = client.Subscribe(context.Background(), "nftest2", nc, "hangSubscription", 999)
- errc <- err
- }()
-
- <-service.gotHangSubscriptionReq
- client.Close()
- service.unblockHangSubscription <- struct{}{}
-
- select {
- case err := <-errc:
- if err == nil {
- t.Errorf("Subscribe returned nil error after Close")
- }
- if sub != nil {
- t.Error("Subscribe returned non-nil subscription after Close")
- }
- case <-time.After(1 * time.Second):
- t.Fatalf("Subscribe did not return within 1s after Close")
- }
-}
-
-// This test reproduces https://github.com/ethereum/go-ethereum/issues/17837 where the
-// client hangs during shutdown when Unsubscribe races with Client.Close.
-func TestClientCloseUnsubscribeRace(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
-
- for i := 0; i < 20; i++ {
- client := DialInProc(server)
- nc := make(chan int)
- sub, err := client.Subscribe(context.Background(), "nftest", nc, "someSubscription", 3, 1)
- if err != nil {
- t.Fatal(err)
- }
- go client.Close()
- go sub.Unsubscribe()
- select {
- case <-sub.Err():
- case <-time.After(5 * time.Second):
- t.Fatal("subscription not closed within timeout")
- }
- }
-}
-
-// This test checks that Client doesn't lock up when a single subscriber
-// doesn't read subscription events.
-func TestClientNotificationStorm(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
-
- doTest := func(count int, wantError bool) {
- client := DialInProc(server)
- defer client.Close()
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Subscribe on the server. It will start sending many notifications
- // very quickly.
- nc := make(chan int)
- sub, err := client.Subscribe(ctx, "nftest", nc, "someSubscription", count, 0)
- if err != nil {
- t.Fatal("can't subscribe:", err)
- }
- defer sub.Unsubscribe()
-
- // Process each notification, try to run a call in between each of them.
- for i := 0; i < count; i++ {
- select {
- case val := <-nc:
- if val != i {
- t.Fatalf("(%d/%d) unexpected value %d", i, count, val)
- }
- case err := <-sub.Err():
- if wantError && err != ErrSubscriptionQueueOverflow {
- t.Fatalf("(%d/%d) got error %q, want %q", i, count, err, ErrSubscriptionQueueOverflow)
- } else if !wantError {
- t.Fatalf("(%d/%d) got unexpected error %q", i, count, err)
- }
- return
- }
- var r int
- err := client.CallContext(ctx, &r, "nftest_echo", i)
- if err != nil {
- if !wantError {
- t.Fatalf("(%d/%d) call error: %v", i, count, err)
- }
- return
- }
- }
- if wantError {
- t.Fatalf("didn't get expected error")
- }
- }
-
- doTest(8000, false)
- doTest(21000, true)
-}
-
-func TestClientHTTP(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
-
- client, hs := httpTestClient(server, "http", nil)
- defer hs.Close()
- defer client.Close()
-
- // Launch concurrent requests.
- var (
- results = make([]Result, 100)
- errc = make(chan error)
- wantResult = Result{"a", 1, new(Args)}
- )
- defer client.Close()
- for i := range results {
- i := i
- go func() {
- errc <- client.Call(&results[i], "test_echo",
- wantResult.String, wantResult.Int, wantResult.Args)
- }()
- }
-
- // Wait for all of them to complete.
- timeout := time.NewTimer(5 * time.Second)
- defer timeout.Stop()
- for i := range results {
- select {
- case err := <-errc:
- if err != nil {
- t.Fatal(err)
- }
- case <-timeout.C:
- t.Fatalf("timeout (got %d/%d) results)", i+1, len(results))
- }
- }
-
- // Check results.
- for i := range results {
- if !reflect.DeepEqual(results[i], wantResult) {
- t.Errorf("result %d mismatch: got %#v, want %#v", i, results[i], wantResult)
- }
- }
-}
-
-func TestClientReconnect(t *testing.T) {
- startServer := func(addr string) (*Server, net.Listener) {
- srv := newTestServer()
- l, err := net.Listen("tcp", addr)
- if err != nil {
- t.Fatal("can't listen:", err)
- }
- go http.Serve(l, srv.WebsocketHandler([]string{"*"}))
- return srv, l
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second)
- defer cancel()
-
- // Start a server and corresponding client.
- s1, l1 := startServer("127.0.0.1:0")
- client, err := DialContext(ctx, "ws://"+l1.Addr().String())
- if err != nil {
- t.Fatal("can't dial", err)
- }
-
- // Perform a call. This should work because the server is up.
- var resp Result
- if err := client.CallContext(ctx, &resp, "test_echo", "", 1, nil); err != nil {
- t.Fatal(err)
- }
-
- // Shut down the server and allow for some cool down time so we can listen on the same
- // address again.
- l1.Close()
- s1.Stop()
- time.Sleep(2 * time.Second)
-
- // Try calling again. It shouldn't work.
- if err := client.CallContext(ctx, &resp, "test_echo", "", 2, nil); err == nil {
- t.Error("successful call while the server is down")
- t.Logf("resp: %#v", resp)
- }
-
- // Start it up again and call again. The connection should be reestablished.
- // We spawn multiple calls here to check whether this hangs somehow.
- s2, l2 := startServer(l1.Addr().String())
- defer l2.Close()
- defer s2.Stop()
-
- start := make(chan struct{})
- errors := make(chan error, 20)
- for i := 0; i < cap(errors); i++ {
- go func() {
- <-start
- var resp Result
- errors <- client.CallContext(ctx, &resp, "test_echo", "", 3, nil)
- }()
- }
- close(start)
- errcount := 0
- for i := 0; i < cap(errors); i++ {
- if err = <-errors; err != nil {
- errcount++
- }
- }
- t.Logf("%d errors, last error: %v", errcount, err)
- if errcount > 1 {
- t.Errorf("expected one error after disconnect, got %d", errcount)
- }
-}
-
-func httpTestClient(srv *Server, transport string, fl *flakeyListener) (*Client, *httptest.Server) {
- // Create the HTTP server.
- var hs *httptest.Server
- switch transport {
- case "ws":
- hs = httptest.NewUnstartedServer(srv.WebsocketHandler([]string{"*"}))
- case "http":
- hs = httptest.NewUnstartedServer(srv)
- default:
- panic("unknown HTTP transport: " + transport)
- }
- // Wrap the listener if required.
- if fl != nil {
- fl.Listener = hs.Listener
- hs.Listener = fl
- }
- // Connect the client.
- hs.Start()
- client, err := Dial(transport + "://" + hs.Listener.Addr().String())
- if err != nil {
- panic(err)
- }
- return client, hs
-}
-
-func ipcTestClient(srv *Server, fl *flakeyListener) (*Client, net.Listener) {
- // Listen on a random endpoint.
- endpoint := fmt.Sprintf("go-ethereum-test-ipc-%d-%d", os.Getpid(), rand.Int63())
- if runtime.GOOS == "windows" {
- endpoint = `\\.\pipe\` + endpoint
- } else {
- endpoint = os.TempDir() + "/" + endpoint
- }
- l, err := ipcListen(endpoint)
- if err != nil {
- panic(err)
- }
- // Connect the listener to the server.
- if fl != nil {
- fl.Listener = l
- l = fl
- }
- go srv.ServeListener(l)
- // Connect the client.
- client, err := Dial(endpoint)
- if err != nil {
- panic(err)
- }
- return client, l
-}
-
-// flakeyListener kills accepted connections after a random timeout.
-type flakeyListener struct {
- net.Listener
- maxKillTimeout time.Duration
- maxAcceptDelay time.Duration
-}
-
-func (l *flakeyListener) Accept() (net.Conn, error) {
- delay := time.Duration(rand.Int63n(int64(l.maxAcceptDelay)))
- time.Sleep(delay)
-
- c, err := l.Listener.Accept()
- if err == nil {
- timeout := time.Duration(rand.Int63n(int64(l.maxKillTimeout)))
- time.AfterFunc(timeout, func() {
- log.Debug(fmt.Sprintf("killing conn %v after %v", c.LocalAddr(), timeout))
- c.Close()
- })
- }
- return c, err
-}
diff --git a/rpc/http_test.go b/rpc/http_test.go
deleted file mode 100644
index b3f694d..0000000
--- a/rpc/http_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2017 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
-)
-
-func TestHTTPErrorResponseWithDelete(t *testing.T) {
- testHTTPErrorResponse(t, http.MethodDelete, contentType, "", http.StatusMethodNotAllowed)
-}
-
-func TestHTTPErrorResponseWithPut(t *testing.T) {
- testHTTPErrorResponse(t, http.MethodPut, contentType, "", http.StatusMethodNotAllowed)
-}
-
-func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) {
- body := make([]rune, maxRequestContentLength+1)
- testHTTPErrorResponse(t,
- http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge)
-}
-
-func TestHTTPErrorResponseWithEmptyContentType(t *testing.T) {
- testHTTPErrorResponse(t, http.MethodPost, "", "", http.StatusUnsupportedMediaType)
-}
-
-func TestHTTPErrorResponseWithValidRequest(t *testing.T) {
- testHTTPErrorResponse(t, http.MethodPost, contentType, "", 0)
-}
-
-func testHTTPErrorResponse(t *testing.T, method, contentType, body string, expected int) {
- request := httptest.NewRequest(method, "http://url.com", strings.NewReader(body))
- request.Header.Set("content-type", contentType)
- if code, _ := validateRequest(request); code != expected {
- t.Fatalf("response code should be %d not %d", expected, code)
- }
-}
diff --git a/rpc/server_test.go b/rpc/server_test.go
deleted file mode 100644
index 3909954..0000000
--- a/rpc/server_test.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "bufio"
- "bytes"
- "io"
- "io/ioutil"
- "net"
- "path/filepath"
- "strings"
- "testing"
- "time"
-)
-
-func TestServerRegisterName(t *testing.T) {
- server := NewServer()
- service := new(testService)
-
- if err := server.RegisterName("test", service); err != nil {
- t.Fatalf("%v", err)
- }
-
- if len(server.services.services) != 2 {
- t.Fatalf("Expected 2 service entries, got %d", len(server.services.services))
- }
-
- svc, ok := server.services.services["test"]
- if !ok {
- t.Fatalf("Expected service calc to be registered")
- }
-
- wantCallbacks := 7
- if len(svc.callbacks) != wantCallbacks {
- t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks))
- }
-}
-
-func TestServer(t *testing.T) {
- files, err := ioutil.ReadDir("testdata")
- if err != nil {
- t.Fatal("where'd my testdata go?")
- }
- for _, f := range files {
- if f.IsDir() || strings.HasPrefix(f.Name(), ".") {
- continue
- }
- path := filepath.Join("testdata", f.Name())
- name := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
- t.Run(name, func(t *testing.T) {
- runTestScript(t, path)
- })
- }
-}
-
-func runTestScript(t *testing.T, file string) {
- server := newTestServer()
- content, err := ioutil.ReadFile(file)
- if err != nil {
- t.Fatal(err)
- }
-
- clientConn, serverConn := net.Pipe()
- defer clientConn.Close()
- go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions)
- readbuf := bufio.NewReader(clientConn)
- for _, line := range strings.Split(string(content), "\n") {
- line = strings.TrimSpace(line)
- switch {
- case len(line) == 0 || strings.HasPrefix(line, "//"):
- // skip comments, blank lines
- continue
- case strings.HasPrefix(line, "--> "):
- t.Log(line)
- // write to connection
- clientConn.SetWriteDeadline(time.Now().Add(5 * time.Second))
- if _, err := io.WriteString(clientConn, line[4:]+"\n"); err != nil {
- t.Fatalf("write error: %v", err)
- }
- case strings.HasPrefix(line, "<-- "):
- t.Log(line)
- want := line[4:]
- // read line from connection and compare text
- clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
- sent, err := readbuf.ReadString('\n')
- if err != nil {
- t.Fatalf("read error: %v", err)
- }
- sent = strings.TrimRight(sent, "\r\n")
- if sent != want {
- t.Errorf("wrong line from server\ngot: %s\nwant: %s", sent, want)
- }
- default:
- panic("invalid line in test script: " + line)
- }
- }
-}
-
-// This test checks that responses are delivered for very short-lived connections that
-// only carry a single request.
-func TestServerShortLivedConn(t *testing.T) {
- server := newTestServer()
- defer server.Stop()
-
- listener, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatal("can't listen:", err)
- }
- defer listener.Close()
- go server.ServeListener(listener)
-
- var (
- request = `{"jsonrpc":"2.0","id":1,"method":"rpc_modules"}` + "\n"
- wantResp = `{"jsonrpc":"2.0","id":1,"result":{"nftest":"1.0","rpc":"1.0","test":"1.0"}}` + "\n"
- deadline = time.Now().Add(10 * time.Second)
- )
- for i := 0; i < 20; i++ {
- conn, err := net.Dial("tcp", listener.Addr().String())
- if err != nil {
- t.Fatal("can't dial:", err)
- }
- defer conn.Close()
- conn.SetDeadline(deadline)
- // Write the request, then half-close the connection so the server stops reading.
- conn.Write([]byte(request))
- conn.(*net.TCPConn).CloseWrite()
- // Now try to get the response.
- buf := make([]byte, 2000)
- n, err := conn.Read(buf)
- if err != nil {
- t.Fatal("read error:", err)
- }
- if !bytes.Equal(buf[:n], []byte(wantResp)) {
- t.Fatalf("wrong response: %s", buf[:n])
- }
- }
-}
diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go
deleted file mode 100644
index eba1924..0000000
--- a/rpc/subscription_test.go
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "strings"
- "testing"
- "time"
-)
-
-func TestNewID(t *testing.T) {
- hexchars := "0123456789ABCDEFabcdef"
- for i := 0; i < 100; i++ {
- id := string(NewID())
- if !strings.HasPrefix(id, "0x") {
- t.Fatalf("invalid ID prefix, want '0x...', got %s", id)
- }
-
- id = id[2:]
- if len(id) == 0 || len(id) > 32 {
- t.Fatalf("invalid ID length, want len(id) > 0 && len(id) <= 32), got %d", len(id))
- }
-
- for i := 0; i < len(id); i++ {
- if strings.IndexByte(hexchars, id[i]) == -1 {
- t.Fatalf("unexpected byte, want any valid hex char, got %c", id[i])
- }
- }
- }
-}
-
-func TestSubscriptions(t *testing.T) {
- var (
- namespaces = []string{"eth", "shh", "bzz"}
- service = &notificationTestService{}
- subCount = len(namespaces)
- notificationCount = 3
-
- server = NewServer()
- clientConn, serverConn = net.Pipe()
- out = json.NewEncoder(clientConn)
- in = json.NewDecoder(clientConn)
- successes = make(chan subConfirmation)
- notifications = make(chan subscriptionResult)
- errors = make(chan error, subCount*notificationCount+1)
- )
-
- // setup and start server
- for _, namespace := range namespaces {
- if err := server.RegisterName(namespace, service); err != nil {
- t.Fatalf("unable to register test service %v", err)
- }
- }
- go server.ServeCodec(NewJSONCodec(serverConn), OptionMethodInvocation|OptionSubscriptions)
- defer server.Stop()
-
- // wait for message and write them to the given channels
- go waitForMessages(in, successes, notifications, errors)
-
- // create subscriptions one by one
- for i, namespace := range namespaces {
- request := map[string]interface{}{
- "id": i,
- "method": fmt.Sprintf("%s_subscribe", namespace),
- "version": "2.0",
- "params": []interface{}{"someSubscription", notificationCount, i},
- }
- if err := out.Encode(&request); err != nil {
- t.Fatalf("Could not create subscription: %v", err)
- }
- }
-
- timeout := time.After(30 * time.Second)
- subids := make(map[string]string, subCount)
- count := make(map[string]int, subCount)
- allReceived := func() bool {
- done := len(count) == subCount
- for _, c := range count {
- if c < notificationCount {
- done = false
- }
- }
- return done
- }
- for !allReceived() {
- select {
- case confirmation := <-successes: // subscription created
- subids[namespaces[confirmation.reqid]] = string(confirmation.subid)
- case notification := <-notifications:
- count[notification.ID]++
- case err := <-errors:
- t.Fatal(err)
- case <-timeout:
- for _, namespace := range namespaces {
- subid, found := subids[namespace]
- if !found {
- t.Errorf("subscription for %q not created", namespace)
- continue
- }
- if count, found := count[subid]; !found || count < notificationCount {
- t.Errorf("didn't receive all notifications (%d<%d) in time for namespace %q", count, notificationCount, namespace)
- }
- }
- t.Fatal("timed out")
- }
- }
-}
-
-// This test checks that unsubscribing works.
-func TestServerUnsubscribe(t *testing.T) {
- // Start the server.
- server := newTestServer()
- service := &notificationTestService{unsubscribed: make(chan string)}
- server.RegisterName("nftest2", service)
- p1, p2 := net.Pipe()
- go server.ServeCodec(NewJSONCodec(p1), OptionMethodInvocation|OptionSubscriptions)
-
- p2.SetDeadline(time.Now().Add(10 * time.Second))
-
- // Subscribe.
- p2.Write([]byte(`{"jsonrpc":"2.0","id":1,"method":"nftest2_subscribe","params":["someSubscription",0,10]}`))
-
- // Handle received messages.
- resps := make(chan subConfirmation)
- notifications := make(chan subscriptionResult)
- errors := make(chan error)
- go waitForMessages(json.NewDecoder(p2), resps, notifications, errors)
-
- // Receive the subscription ID.
- var sub subConfirmation
- select {
- case sub = <-resps:
- case err := <-errors:
- t.Fatal(err)
- }
-
- // Unsubscribe and check that it is handled on the server side.
- p2.Write([]byte(`{"jsonrpc":"2.0","method":"nftest2_unsubscribe","params":["` + sub.subid + `"]}`))
- for {
- select {
- case id := <-service.unsubscribed:
- if id != string(sub.subid) {
- t.Errorf("wrong subscription ID unsubscribed")
- }
- return
- case err := <-errors:
- t.Fatal(err)
- case <-notifications:
- // drop notifications
- }
- }
-}
-
-type subConfirmation struct {
- reqid int
- subid ID
-}
-
-func waitForMessages(in *json.Decoder, successes chan subConfirmation, notifications chan subscriptionResult, errors chan error) {
- for {
- var msg jsonrpcMessage
- if err := in.Decode(&msg); err != nil {
- errors <- fmt.Errorf("decode error: %v", err)
- return
- }
- switch {
- case msg.isNotification():
- var res subscriptionResult
- if err := json.Unmarshal(msg.Params, &res); err != nil {
- errors <- fmt.Errorf("invalid subscription result: %v", err)
- } else {
- notifications <- res
- }
- case msg.isResponse():
- var c subConfirmation
- if msg.Error != nil {
- errors <- msg.Error
- } else if err := json.Unmarshal(msg.Result, &c.subid); err != nil {
- errors <- fmt.Errorf("invalid response: %v", err)
- } else {
- json.Unmarshal(msg.ID, &c.reqid)
- successes <- c
- }
- default:
- errors <- fmt.Errorf("unrecognized message: %v", msg)
- return
- }
- }
-}
diff --git a/rpc/testservice_test.go b/rpc/testservice_test.go
deleted file mode 100644
index 98871b5..0000000
--- a/rpc/testservice_test.go
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2019 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "context"
- "encoding/binary"
- "errors"
- "sync"
- "time"
-)
-
-func newTestServer() *Server {
- server := NewServer()
- server.idgen = sequentialIDGenerator()
- if err := server.RegisterName("test", new(testService)); err != nil {
- panic(err)
- }
- if err := server.RegisterName("nftest", new(notificationTestService)); err != nil {
- panic(err)
- }
- return server
-}
-
-func sequentialIDGenerator() func() ID {
- var (
- mu sync.Mutex
- counter uint64
- )
- return func() ID {
- mu.Lock()
- defer mu.Unlock()
- counter++
- id := make([]byte, 8)
- binary.BigEndian.PutUint64(id, counter)
- return encodeID(id)
- }
-}
-
-type testService struct{}
-
-type Args struct {
- S string
-}
-
-type Result struct {
- String string
- Int int
- Args *Args
-}
-
-func (s *testService) NoArgsRets() {}
-
-func (s *testService) Echo(str string, i int, args *Args) Result {
- return Result{str, i, args}
-}
-
-func (s *testService) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result {
- return Result{str, i, args}
-}
-
-func (s *testService) Sleep(ctx context.Context, duration time.Duration) {
- time.Sleep(duration)
-}
-
-func (s *testService) Rets() (string, error) {
- return "", nil
-}
-
-func (s *testService) InvalidRets1() (error, string) {
- return nil, ""
-}
-
-func (s *testService) InvalidRets2() (string, string) {
- return "", ""
-}
-
-func (s *testService) InvalidRets3() (string, string, error) {
- return "", "", nil
-}
-
-func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) {
- c, ok := ClientFromContext(ctx)
- if !ok {
- return nil, errors.New("no client")
- }
- var result interface{}
- err := c.Call(&result, method, args...)
- return result, err
-}
-
-func (s *testService) CallMeBackLater(ctx context.Context, method string, args []interface{}) error {
- c, ok := ClientFromContext(ctx)
- if !ok {
- return errors.New("no client")
- }
- go func() {
- <-ctx.Done()
- var result interface{}
- c.Call(&result, method, args...)
- }()
- return nil
-}
-
-func (s *testService) Subscription(ctx context.Context) (*Subscription, error) {
- return nil, nil
-}
-
-type notificationTestService struct {
- unsubscribed chan string
- gotHangSubscriptionReq chan struct{}
- unblockHangSubscription chan struct{}
-}
-
-func (s *notificationTestService) Echo(i int) int {
- return i
-}
-
-func (s *notificationTestService) Unsubscribe(subid string) {
- if s.unsubscribed != nil {
- s.unsubscribed <- subid
- }
-}
-
-func (s *notificationTestService) SomeSubscription(ctx context.Context, n, val int) (*Subscription, error) {
- notifier, supported := NotifierFromContext(ctx)
- if !supported {
- return nil, ErrNotificationsUnsupported
- }
-
- // By explicitly creating an subscription we make sure that the subscription id is send
- // back to the client before the first subscription.Notify is called. Otherwise the
- // events might be send before the response for the *_subscribe method.
- subscription := notifier.CreateSubscription()
- go func() {
- for i := 0; i < n; i++ {
- if err := notifier.Notify(subscription.ID, val+i); err != nil {
- return
- }
- }
- select {
- case <-notifier.Closed():
- case <-subscription.Err():
- }
- if s.unsubscribed != nil {
- s.unsubscribed <- string(subscription.ID)
- }
- }()
- return subscription, nil
-}
-
-// HangSubscription blocks on s.unblockHangSubscription before sending anything.
-func (s *notificationTestService) HangSubscription(ctx context.Context, val int) (*Subscription, error) {
- notifier, supported := NotifierFromContext(ctx)
- if !supported {
- return nil, ErrNotificationsUnsupported
- }
- s.gotHangSubscriptionReq <- struct{}{}
- <-s.unblockHangSubscription
- subscription := notifier.CreateSubscription()
-
- go func() {
- notifier.Notify(subscription.ID, val)
- }()
- return subscription, nil
-}
diff --git a/rpc/types_test.go b/rpc/types_test.go
deleted file mode 100644
index 0465849..0000000
--- a/rpc/types_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/ava-labs/go-ethereum/common/math"
-)
-
-func TestBlockNumberJSONUnmarshal(t *testing.T) {
- tests := []struct {
- input string
- mustFail bool
- expected BlockNumber
- }{
- 0: {`"0x"`, true, BlockNumber(0)},
- 1: {`"0x0"`, false, BlockNumber(0)},
- 2: {`"0X1"`, false, BlockNumber(1)},
- 3: {`"0x00"`, true, BlockNumber(0)},
- 4: {`"0x01"`, true, BlockNumber(0)},
- 5: {`"0x1"`, false, BlockNumber(1)},
- 6: {`"0x12"`, false, BlockNumber(18)},
- 7: {`"0x7fffffffffffffff"`, false, BlockNumber(math.MaxInt64)},
- 8: {`"0x8000000000000000"`, true, BlockNumber(0)},
- 9: {"0", true, BlockNumber(0)},
- 10: {`"ff"`, true, BlockNumber(0)},
- 11: {`"pending"`, false, PendingBlockNumber},
- 12: {`"latest"`, false, LatestBlockNumber},
- 13: {`"earliest"`, false, EarliestBlockNumber},
- 14: {`someString`, true, BlockNumber(0)},
- 15: {`""`, true, BlockNumber(0)},
- 16: {``, true, BlockNumber(0)},
- }
-
- for i, test := range tests {
- var num BlockNumber
- err := json.Unmarshal([]byte(test.input), &num)
- if test.mustFail && err == nil {
- t.Errorf("Test %d should fail", i)
- continue
- }
- if !test.mustFail && err != nil {
- t.Errorf("Test %d should pass but got err: %v", i, err)
- continue
- }
- if num != test.expected {
- t.Errorf("Test %d got unexpected value, want %d, got %d", i, test.expected, num)
- }
- }
-}
diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go
deleted file mode 100644
index 9dc1084..0000000
--- a/rpc/websocket_test.go
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
- "context"
- "net"
- "net/http"
- "net/http/httptest"
- "reflect"
- "strings"
- "testing"
- "time"
-
- "github.com/gorilla/websocket"
-)
-
-func TestWebsocketClientHeaders(t *testing.T) {
- t.Parallel()
-
- endpoint, header, err := wsClientHeaders("wss://testuser:[email protected]:1234", "https://example.com")
- if err != nil {
- t.Fatalf("wsGetConfig failed: %s", err)
- }
- if endpoint != "wss://example.com:1234" {
- t.Fatal("User should have been stripped from the URL")
- }
- if header.Get("authorization") != "Basic dGVzdHVzZXI6dGVzdC1QQVNTXzAx" {
- t.Fatal("Basic auth header is incorrect")
- }
- if header.Get("origin") != "https://example.com" {
- t.Fatal("Origin not set")
- }
-}
-
-// This test checks that the server rejects connections from disallowed origins.
-func TestWebsocketOriginCheck(t *testing.T) {
- t.Parallel()
-
- var (
- srv = newTestServer()
- httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"http://example.com"}))
- wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:")
- )
- defer srv.Stop()
- defer httpsrv.Close()
-
- client, err := DialWebsocket(context.Background(), wsURL, "http://ekzample.com")
- if err == nil {
- client.Close()
- t.Fatal("no error for wrong origin")
- }
- wantErr := wsHandshakeError{websocket.ErrBadHandshake, "403 Forbidden"}
- if !reflect.DeepEqual(err, wantErr) {
- t.Fatalf("wrong error for wrong origin: %q", err)
- }
-
- // Connections without origin header should work.
- client, err = DialWebsocket(context.Background(), wsURL, "")
- if err != nil {
- t.Fatal("error for empty origin")
- }
- client.Close()
-}
-
-// This test checks whether calls exceeding the request size limit are rejected.
-func TestWebsocketLargeCall(t *testing.T) {
- t.Parallel()
-
- var (
- srv = newTestServer()
- httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"}))
- wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:")
- )
- defer srv.Stop()
- defer httpsrv.Close()
-
- client, err := DialWebsocket(context.Background(), wsURL, "")
- if err != nil {
- t.Fatalf("can't dial: %v", err)
- }
- defer client.Close()
-
- // This call sends slightly less than the limit and should work.
- var result Result
- arg := strings.Repeat("x", maxRequestContentLength-200)
- if err := client.Call(&result, "test_echo", arg, 1); err != nil {
- t.Fatalf("valid call didn't work: %v", err)
- }
- if result.String != arg {
- t.Fatal("wrong string echoed")
- }
-
- // This call sends twice the allowed size and shouldn't work.
- arg = strings.Repeat("x", maxRequestContentLength*2)
- err = client.Call(&result, "test_echo", arg)
- if err == nil {
- t.Fatal("no error for too large call")
- }
-}
-
-// This test checks that client handles WebSocket ping frames correctly.
-func TestClientWebsocketPing(t *testing.T) {
- t.Parallel()
-
- var (
- sendPing = make(chan struct{})
- server = wsPingTestServer(t, sendPing)
- ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
- )
- defer cancel()
- defer server.Shutdown(ctx)
-
- client, err := DialContext(ctx, "ws://"+server.Addr)
- if err != nil {
- t.Fatalf("client dial error: %v", err)
- }
- resultChan := make(chan int)
- sub, err := client.EthSubscribe(ctx, resultChan, "foo")
- if err != nil {
- t.Fatalf("client subscribe error: %v", err)
- }
-
- // Wait for the context's deadline to be reached before proceeding.
- // This is important for reproducing https://github.com/ethereum/go-ethereum/issues/19798
- <-ctx.Done()
- close(sendPing)
-
- // Wait for the subscription result.
- timeout := time.NewTimer(5 * time.Second)
- for {
- select {
- case err := <-sub.Err():
- t.Error("client subscription error:", err)
- case result := <-resultChan:
- t.Log("client got result:", result)
- return
- case <-timeout.C:
- t.Error("didn't get any result within the test timeout")
- return
- }
- }
-}
-
-// wsPingTestServer runs a WebSocket server which accepts a single subscription request.
-// When a value arrives on sendPing, the server sends a ping frame, waits for a matching
-// pong and finally delivers a single subscription result.
-func wsPingTestServer(t *testing.T, sendPing <-chan struct{}) *http.Server {
- var srv http.Server
- shutdown := make(chan struct{})
- srv.RegisterOnShutdown(func() {
- close(shutdown)
- })
- srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // Upgrade to WebSocket.
- upgrader := websocket.Upgrader{
- CheckOrigin: func(r *http.Request) bool { return true },
- }
- conn, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- t.Errorf("server WS upgrade error: %v", err)
- return
- }
- defer conn.Close()
-
- // Handle the connection.
- wsPingTestHandler(t, conn, shutdown, sendPing)
- })
-
- // Start the server.
- listener, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatal("can't listen:", err)
- }
- srv.Addr = listener.Addr().String()
- go srv.Serve(listener)
- return &srv
-}
-
-func wsPingTestHandler(t *testing.T, conn *websocket.Conn, shutdown, sendPing <-chan struct{}) {
- // Canned responses for the eth_subscribe call in TestClientWebsocketPing.
- const (
- subResp = `{"jsonrpc":"2.0","id":1,"result":"0x00"}`
- subNotify = `{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x00","result":1}}`
- )
-
- // Handle subscribe request.
- if _, _, err := conn.ReadMessage(); err != nil {
- t.Errorf("server read error: %v", err)
- return
- }
- if err := conn.WriteMessage(websocket.TextMessage, []byte(subResp)); err != nil {
- t.Errorf("server write error: %v", err)
- return
- }
-
- // Read from the connection to process control messages.
- var pongCh = make(chan string)
- conn.SetPongHandler(func(d string) error {
- t.Logf("server got pong: %q", d)
- pongCh <- d
- return nil
- })
- go func() {
- for {
- typ, msg, err := conn.ReadMessage()
- if err != nil {
- return
- }
- t.Logf("server got message (%d): %q", typ, msg)
- }
- }()
-
- // Write messages.
- var (
- sendResponse <-chan time.Time
- wantPong string
- )
- for {
- select {
- case _, open := <-sendPing:
- if !open {
- sendPing = nil
- }
- t.Logf("server sending ping")
- conn.WriteMessage(websocket.PingMessage, []byte("ping"))
- wantPong = "ping"
- case data := <-pongCh:
- if wantPong == "" {
- t.Errorf("unexpected pong")
- } else if data != wantPong {
- t.Errorf("got pong with wrong data %q", data)
- }
- wantPong = ""
- sendResponse = time.NewTimer(200 * time.Millisecond).C
- case <-sendResponse:
- t.Logf("server sending response")
- conn.WriteMessage(websocket.TextMessage, []byte(subNotify))
- sendResponse = nil
- case <-shutdown:
- conn.Close()
- return
- }
- }
-}