good morning!!!!

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • github/maticnetwork/bor
  • open/bor
2 results
Show changes
Commits on Source (45)
Showing
with 437 additions and 79 deletions
...@@ -13,3 +13,8 @@ jobs: ...@@ -13,3 +13,8 @@ jobs:
run: make all run: make all
- name: "Run tests" - name: "Run tests"
run: make test run: make test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: ./cover.out
...@@ -20,7 +20,7 @@ builds: ...@@ -20,7 +20,7 @@ builds:
- netgo - netgo
ldflags: ldflags:
-s -w -s -w
- id: darwin-arm64 - id: darwin-arm64
main: ./cmd/geth main: ./cmd/geth
binary: bor binary: bor
...@@ -35,7 +35,7 @@ builds: ...@@ -35,7 +35,7 @@ builds:
- netgo - netgo
ldflags: ldflags:
-s -w -s -w
- id: linux-amd64 - id: linux-amd64
main: ./cmd/geth main: ./cmd/geth
binary: bor binary: bor
...@@ -49,7 +49,7 @@ builds: ...@@ -49,7 +49,7 @@ builds:
tags: tags:
- netgo - netgo
ldflags: ldflags:
# We need to build a static binary because we are building in a glibc based system and running in a musl container # We need to build a static binary because we are building in a glibc based system and running in a musl container
-s -w -extldflags "-static" -s -w -extldflags "-static"
- id: linux-arm64 - id: linux-arm64
...@@ -65,7 +65,7 @@ builds: ...@@ -65,7 +65,7 @@ builds:
tags: tags:
- netgo - netgo
ldflags: ldflags:
# We need to build a static binary because we are building in a glibc based system and running in a musl container # We need to build a static binary because we are building in a glibc based system and running in a musl container
-s -w -extldflags "-static" -s -w -extldflags "-static"
nfpms: nfpms:
...@@ -112,7 +112,7 @@ dockers: ...@@ -112,7 +112,7 @@ dockers:
extra_files: extra_files:
- builder/files/genesis-mainnet-v1.json - builder/files/genesis-mainnet-v1.json
- builder/files/genesis-testnet-v4.json - builder/files/genesis-testnet-v4.json
- image_templates: - image_templates:
- 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64 - 0xpolygon/{{ .ProjectName }}:{{ .Version }}-arm64
dockerfile: Dockerfile.release dockerfile: Dockerfile.release
......
...@@ -48,10 +48,9 @@ ios: ...@@ -48,10 +48,9 @@ ios:
@echo "Done building." @echo "Done building."
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library." @echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
test: all test:
# $(GORUN) build/ci.go test
# Skip mobile and cmd tests since they are being deprecated # Skip mobile and cmd tests since they are being deprecated
go test -v $(go list ./... | grep -v go-ethereum/cmd/ | grep -v go-ethereum/mobile/) go test -v $$(go list ./... | grep -v go-ethereum/cmd/) -cover -coverprofile=cover.out
lint: ## Run linters. lint: ## Run linters.
$(GORUN) build/ci.go lint $(GORUN) build/ci.go lint
......
...@@ -116,6 +116,9 @@ var ( ...@@ -116,6 +116,9 @@ var (
// errOutOfRangeChain is returned if an authorization list is attempted to // errOutOfRangeChain is returned if an authorization list is attempted to
// be modified via out-of-range or non-contiguous headers. // be modified via out-of-range or non-contiguous headers.
errOutOfRangeChain = errors.New("out of range or non-contiguous chain") errOutOfRangeChain = errors.New("out of range or non-contiguous chain")
// errShutdownDetected is returned if a shutdown was detected
errShutdownDetected = errors.New("shutdown detected")
) )
// SignerFn is a signer callback function to request a header to be signed by a // SignerFn is a signer callback function to request a header to be signed by a
...@@ -916,6 +919,7 @@ func (c *Bor) APIs(chain consensus.ChainHeaderReader) []rpc.API { ...@@ -916,6 +919,7 @@ func (c *Bor) APIs(chain consensus.ChainHeaderReader) []rpc.API {
// Close implements consensus.Engine. It's a noop for bor as there are no background threads. // Close implements consensus.Engine. It's a noop for bor as there are no background threads.
func (c *Bor) Close() error { func (c *Bor) Close() error {
c.HeimdallClient.Close()
return nil return nil
} }
......
...@@ -27,11 +27,13 @@ type IHeimdallClient interface { ...@@ -27,11 +27,13 @@ type IHeimdallClient interface {
Fetch(path string, query string) (*ResponseWithHeight, error) Fetch(path string, query string) (*ResponseWithHeight, error)
FetchWithRetry(path string, query string) (*ResponseWithHeight, error) FetchWithRetry(path string, query string) (*ResponseWithHeight, error)
FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error)
Close()
} }
type HeimdallClient struct { type HeimdallClient struct {
urlString string urlString string
client http.Client client http.Client
closeCh chan struct{}
} }
func NewHeimdallClient(urlString string) (*HeimdallClient, error) { func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
...@@ -40,6 +42,7 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) { ...@@ -40,6 +42,7 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
client: http.Client{ client: http.Client{
Timeout: time.Duration(5 * time.Second), Timeout: time.Duration(5 * time.Second),
}, },
closeCh: make(chan struct{}),
} }
return h, nil return h, nil
} }
...@@ -96,13 +99,22 @@ func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*Respo ...@@ -96,13 +99,22 @@ func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*Respo
u.Path = rawPath u.Path = rawPath
u.RawQuery = rawQuery u.RawQuery = rawQuery
// create a new ticker for retrying the request
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for { for {
res, err := h.internalFetch(u) select {
if err == nil && res != nil { case <-h.closeCh:
return res, nil log.Debug("Shutdown detected, terminating request")
return nil, errShutdownDetected
case <-ticker.C:
res, err := h.internalFetch(u)
if err == nil && res != nil {
return res, nil
}
log.Info("Retrying again in 5 seconds for next Heimdall data", "path", u.Path)
} }
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", u.Path)
time.Sleep(5 * time.Second)
} }
} }
...@@ -137,3 +149,9 @@ func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) ...@@ -137,3 +149,9 @@ func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error)
return &response, nil return &response, nil
} }
// Close sends a signal to stop the running process
func (h *HeimdallClient) Close() {
close(h.closeCh)
h.client.CloseIdleConnections()
}
package core
import (
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
func TestChain2HeadEvent(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}},
}
genesis = gspec.MustCommit(db)
signer = types.LatestSigner(gspec.Config)
)
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
defer blockchain.Stop()
chain2HeadCh := make(chan Chain2HeadEvent, 64)
blockchain.SubscribeChain2HeadEvent(chain2HeadCh)
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1)
if i == 2 {
gen.OffsetTime(-9)
}
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
gen.AddTx(tx)
})
if _, err := blockchain.InsertChain(replacementBlocks); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
type eventTest struct {
Type string
Added []common.Hash
Removed []common.Hash
}
readEvent := func(expect *eventTest) {
select {
case ev := <-chain2HeadCh:
if ev.Type != expect.Type {
t.Fatal("Type mismatch")
}
if len(ev.NewChain) != len(expect.Added) {
t.Fatal("Newchain and Added Array Size don't match")
}
if len(ev.OldChain) != len(expect.Removed) {
t.Fatal("Oldchain and Removed Array Size don't match")
}
for j := 0; j < len(ev.OldChain); j++ {
if ev.OldChain[j].Hash() != expect.Removed[j] {
t.Fatal("Oldchain hashes Do Not Match")
}
}
for j := 0; j < len(ev.NewChain); j++ {
if ev.NewChain[j].Hash() != expect.Added[j] {
t.Fatal("Newchain hashes Do Not Match")
}
}
case <-time.After(2 * time.Second):
t.Fatal("timeout")
}
}
// head event
readEvent(&eventTest{
Type: Chain2HeadCanonicalEvent,
Added: []common.Hash{
chain[2].Hash(),
}})
// fork event
readEvent(&eventTest{
Type: Chain2HeadForkEvent,
Added: []common.Hash{
replacementBlocks[0].Hash(),
}})
// fork event
readEvent(&eventTest{
Type: Chain2HeadForkEvent,
Added: []common.Hash{
replacementBlocks[1].Hash(),
}})
// reorg event
//In this event the channel recieves an array of Blocks in NewChain and OldChain
readEvent(&eventTest{
Type: Chain2HeadReorgEvent,
Added: []common.Hash{
replacementBlocks[2].Hash(),
replacementBlocks[1].Hash(),
replacementBlocks[0].Hash(),
},
Removed: []common.Hash{
chain[2].Hash(),
chain[1].Hash(),
chain[0].Hash(),
},
})
// head event
readEvent(&eventTest{
Type: Chain2HeadCanonicalEvent,
Added: []common.Hash{
replacementBlocks[3].Hash(),
}})
}
...@@ -53,6 +53,7 @@ func TestStateProcessorErrors(t *testing.T) { ...@@ -53,6 +53,7 @@ func TestStateProcessorErrors(t *testing.T) {
BerlinBlock: big.NewInt(0), BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0), LondonBlock: big.NewInt(0),
Ethash: new(params.EthashConfig), Ethash: new(params.EthashConfig),
Bor: &params.BorConfig{BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}},
} }
signer = types.LatestSigner(config) signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
......
...@@ -19,18 +19,4 @@ $ bor server ...@@ -19,18 +19,4 @@ $ bor server
$ bor server --config ./legacy.toml $ bor server --config ./legacy.toml
``` ```
- Modules, vhost and Cors configuration are common for all jsonrpc endpoints.
Before:
```
$ bor --http --http.modules "eth,web" --ws --ws.modules "eth,web"
```
Now:
```
$ bor server --http --ws --jsonrpc.modules "eth,web"
```
- ```Admin```, ```Personal``` and account related endpoints in ```Eth``` are being removed from the JsonRPC interface. Some of this functionality will be moved to the new GRPC server for operational tasks. - ```Admin```, ```Personal``` and account related endpoints in ```Eth``` are being removed from the JsonRPC interface. Some of this functionality will be moved to the new GRPC server for operational tasks.
...@@ -109,8 +109,6 @@ The ```bor server``` command runs the Bor client. ...@@ -109,8 +109,6 @@ The ```bor server``` command runs the Bor client.
- ```jsonrpc.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. - ```jsonrpc.vhosts```: Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.
- ```jsonrpc.modules```: API's offered over the HTTP-RPC interface.
- ```http```: Enable the HTTP-RPC server. - ```http```: Enable the HTTP-RPC server.
- ```http.addr```: HTTP-RPC server listening interface. - ```http.addr```: HTTP-RPC server listening interface.
...@@ -119,6 +117,8 @@ The ```bor server``` command runs the Bor client. ...@@ -119,6 +117,8 @@ The ```bor server``` command runs the Bor client.
- ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths. - ```http.rpcprefix```: HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
- ```http.modules```: API's offered over the HTTP-RPC interface.
- ```ws```: Enable the WS-RPC server. - ```ws```: Enable the WS-RPC server.
- ```ws.addr```: WS-RPC server listening interface. - ```ws.addr```: WS-RPC server listening interface.
...@@ -127,6 +127,8 @@ The ```bor server``` command runs the Bor client. ...@@ -127,6 +127,8 @@ The ```bor server``` command runs the Bor client.
- ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths. - ```ws.rpcprefix```: HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.
- ```ws.modules```: API's offered over the WS-RPC interface.
- ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well. - ```graphql```: Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.
### P2P Options ### P2P Options
......
...@@ -581,10 +581,12 @@ func (s *Ethereum) Stop() error { ...@@ -581,10 +581,12 @@ func (s *Ethereum) Stop() error {
// Then stop everything else. // Then stop everything else.
s.bloomIndexer.Close() s.bloomIndexer.Close()
close(s.closeBloomHandler) close(s.closeBloomHandler)
// closing consensus engine first, as miner has deps on it
s.engine.Close()
s.txPool.Stop() s.txPool.Stop()
s.miner.Close()
s.blockchain.Stop() s.blockchain.Stop()
s.engine.Close() s.miner.Close()
rawdb.PopUncleanShutdownMarker(s.chainDb) rawdb.PopUncleanShutdownMarker(s.chainDb)
s.chainDb.Close() s.chainDb.Close()
s.eventMux.Stop() s.eventMux.Stop()
......
...@@ -110,6 +110,8 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, ...@@ -110,6 +110,8 @@ func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block,
*/ */
func TestEth2AssembleBlock(t *testing.T) { func TestEth2AssembleBlock(t *testing.T) {
t.Skip("bor due to burn contract")
genesis, blocks := generateTestChain() genesis, blocks := generateTestChain()
n, ethservice := startEthService(t, genesis, blocks[1:9]) n, ethservice := startEthService(t, genesis, blocks[1:9])
defer n.Close() defer n.Close()
...@@ -137,6 +139,8 @@ func TestEth2AssembleBlock(t *testing.T) { ...@@ -137,6 +139,8 @@ func TestEth2AssembleBlock(t *testing.T) {
} }
func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
t.Skip("bor due to burn contract")
genesis, blocks := generateTestChain() genesis, blocks := generateTestChain()
n, ethservice := startEthService(t, genesis, blocks[1:9]) n, ethservice := startEthService(t, genesis, blocks[1:9])
defer n.Close() defer n.Close()
......
...@@ -229,7 +229,9 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et ...@@ -229,7 +229,9 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et
return clique.New(chainConfig.Clique, db) return clique.New(chainConfig.Clique, db)
} }
// If Matic bor consensus is requested, set it up // If Matic bor consensus is requested, set it up
if chainConfig.Bor != nil { // In order to pass the ethereum transaction tests, we need to set the burn contract which is in the bor config
// Then, bor != nil will also be enabled for ethash and clique. Only enable Bor for real if there is a validator contract present.
if chainConfig.Bor != nil && chainConfig.Bor.ValidatorContract != "" {
return bor.New(chainConfig, db, blockchainAPI, ethConfig.HeimdallURL, ethConfig.WithoutHeimdall) return bor.New(chainConfig, db, blockchainAPI, ethConfig.HeimdallURL, ethConfig.WithoutHeimdall)
} }
// Otherwise assume proof-of-work // Otherwise assume proof-of-work
......
...@@ -234,6 +234,8 @@ func generateTestChain() (*core.Genesis, []*types.Block) { ...@@ -234,6 +234,8 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
} }
func TestEthClient(t *testing.T) { func TestEthClient(t *testing.T) {
t.Skip("bor due to burn contract")
backend, chain := newTestBackend(t) backend, chain := newTestBackend(t)
client, _ := backend.Attach() client, _ := backend.Attach()
defer backend.Close() defer backend.Close()
......
...@@ -89,6 +89,8 @@ func generateTestChain() (*core.Genesis, []*types.Block) { ...@@ -89,6 +89,8 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
} }
func TestGethClient(t *testing.T) { func TestGethClient(t *testing.T) {
t.Skip("bor due to burn contract")
backend, _ := newTestBackend(t) backend, _ := newTestBackend(t)
client, err := backend.Attach() client, err := backend.Attach()
if err != nil { if err != nil {
......
package chains
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
// GetDeveloperChain returns the developer mode configs.
func GetDeveloperChain(period uint64, faucet common.Address) *Chain {
// Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges
config.Clique = &params.CliqueConfig{
Period: period,
Epoch: config.Clique.Epoch,
}
// Assemble and return the chain having genesis with the
// precompiles and faucet pre-funded
return &Chain{
Hash: common.Hash{},
NetworkId: 1337,
Genesis: &core.Genesis{
Config: &config,
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...),
GasLimit: 11500000,
BaseFee: big.NewInt(params.InitialBaseFee),
Difficulty: big.NewInt(1),
Alloc: map[common.Address]core.GenesisAccount{
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD
common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity
common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
},
},
Bootnodes: []string{},
}
}
...@@ -14,6 +14,8 @@ import ( ...@@ -14,6 +14,8 @@ import (
godebug "runtime/debug" godebug "runtime/debug"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
...@@ -91,6 +93,9 @@ type Config struct { ...@@ -91,6 +93,9 @@ type Config struct {
// GRPC has the grpc server related settings // GRPC has the grpc server related settings
GRPC *GRPCConfig GRPC *GRPCConfig
// Developer has the developer mode related settings
Developer *DeveloperConfig
} }
type P2PConfig struct { type P2PConfig struct {
...@@ -209,9 +214,6 @@ type JsonRPCConfig struct { ...@@ -209,9 +214,6 @@ type JsonRPCConfig struct {
// IPCPath is the path of the ipc endpoint // IPCPath is the path of the ipc endpoint
IPCPath string `hcl:"ipc-path,optional"` IPCPath string `hcl:"ipc-path,optional"`
// Modules is the list of enabled api modules
Modules []string `hcl:"modules,optional"`
// VHost is the list of valid virtual hosts // VHost is the list of valid virtual hosts
VHost []string `hcl:"vhost,optional"` VHost []string `hcl:"vhost,optional"`
...@@ -251,6 +253,9 @@ type APIConfig struct { ...@@ -251,6 +253,9 @@ type APIConfig struct {
// Host is the address to bind the api // Host is the address to bind the api
Host string `hcl:"host,optional"` Host string `hcl:"host,optional"`
// Modules is the list of enabled api modules
Modules []string `hcl:"modules,optional"`
} }
type GpoConfig struct { type GpoConfig struct {
...@@ -365,6 +370,14 @@ type AccountsConfig struct { ...@@ -365,6 +370,14 @@ type AccountsConfig struct {
UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"` UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"`
} }
type DeveloperConfig struct {
// Enabled enables the developer mode
Enabled bool `hcl:"dev,optional"`
// Period is the block period to use in developer mode
Period uint64 `hcl:"period,optional"`
}
func DefaultConfig() *Config { func DefaultConfig() *Config {
return &Config{ return &Config{
Chain: "mainnet", Chain: "mainnet",
...@@ -425,7 +438,6 @@ func DefaultConfig() *Config { ...@@ -425,7 +438,6 @@ func DefaultConfig() *Config {
JsonRPC: &JsonRPCConfig{ JsonRPC: &JsonRPCConfig{
IPCDisable: false, IPCDisable: false,
IPCPath: "", IPCPath: "",
Modules: []string{"web3", "net"},
Cors: []string{"*"}, Cors: []string{"*"},
VHost: []string{"*"}, VHost: []string{"*"},
GasCap: ethconfig.Defaults.RPCGasCap, GasCap: ethconfig.Defaults.RPCGasCap,
...@@ -435,12 +447,14 @@ func DefaultConfig() *Config { ...@@ -435,12 +447,14 @@ func DefaultConfig() *Config {
Port: 8545, Port: 8545,
Prefix: "", Prefix: "",
Host: "localhost", Host: "localhost",
Modules: []string{"web3", "net"},
}, },
Ws: &APIConfig{ Ws: &APIConfig{
Enabled: false, Enabled: false,
Port: 8546, Port: 8546,
Prefix: "", Prefix: "",
Host: "localhost", Host: "localhost",
Modules: []string{"web3", "net"},
}, },
Graphql: &APIConfig{ Graphql: &APIConfig{
Enabled: false, Enabled: false,
...@@ -486,6 +500,10 @@ func DefaultConfig() *Config { ...@@ -486,6 +500,10 @@ func DefaultConfig() *Config {
GRPC: &GRPCConfig{ GRPC: &GRPCConfig{
Addr: ":3131", Addr: ":3131",
}, },
Developer: &DeveloperConfig{
Enabled: false,
Period: 0,
},
} }
} }
...@@ -573,6 +591,9 @@ func readConfigFile(path string) (*Config, error) { ...@@ -573,6 +591,9 @@ func readConfigFile(path string) (*Config, error) {
} }
func (c *Config) loadChain() error { func (c *Config) loadChain() error {
if c.Developer.Enabled {
return nil
}
chain, ok := chains.GetChain(c.Chain) chain, ok := chains.GetChain(c.Chain)
if !ok { if !ok {
return fmt.Errorf("chain '%s' not found", c.Chain) return fmt.Errorf("chain '%s' not found", c.Chain)
...@@ -585,7 +606,7 @@ func (c *Config) loadChain() error { ...@@ -585,7 +606,7 @@ func (c *Config) loadChain() error {
} }
// depending on the chain we have different cache values // depending on the chain we have different cache values
if c.Chain != "mainnet" { if c.Chain == "mainnet" {
c.Cache.Cache = 4096 c.Cache.Cache = 4096
} else { } else {
c.Cache.Cache = 1024 c.Cache.Cache = 1024
...@@ -593,14 +614,19 @@ func (c *Config) loadChain() error { ...@@ -593,14 +614,19 @@ func (c *Config) loadChain() error {
return nil return nil
} }
func (c *Config) buildEth() (*ethconfig.Config, error) { func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) {
dbHandles, err := makeDatabaseHandles() dbHandles, err := makeDatabaseHandles()
if err != nil { if err != nil {
return nil, err return nil, err
} }
n := ethconfig.Defaults n := ethconfig.Defaults
n.NetworkId = c.chain.NetworkId
n.Genesis = c.chain.Genesis // only update for non-developer mode as we don't yet
// have the chain object for it.
if !c.Developer.Enabled {
n.NetworkId = c.chain.NetworkId
n.Genesis = c.chain.Genesis
}
n.HeimdallURL = c.Heimdall.URL n.HeimdallURL = c.Heimdall.URL
n.WithoutHeimdall = c.Heimdall.Without n.WithoutHeimdall = c.Heimdall.Without
...@@ -640,6 +666,55 @@ func (c *Config) buildEth() (*ethconfig.Config, error) { ...@@ -640,6 +666,55 @@ func (c *Config) buildEth() (*ethconfig.Config, error) {
} }
} }
// update for developer mode
if c.Developer.Enabled {
// Get a keystore
var ks *keystore.KeyStore
if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
ks = keystores[0].(*keystore.KeyStore)
}
// Create new developer account or reuse existing one
var (
developer accounts.Account
passphrase string
err error
)
// etherbase has been set above, configuring the miner address from command line flags.
if n.Miner.Etherbase != (common.Address{}) {
developer = accounts.Account{Address: n.Miner.Etherbase}
} else if accs := ks.Accounts(); len(accs) > 0 {
developer = ks.Accounts()[0]
} else {
developer, err = ks.NewAccount(passphrase)
if err != nil {
return nil, fmt.Errorf("failed to create developer account: %v", err)
}
}
if err := ks.Unlock(developer, passphrase); err != nil {
return nil, fmt.Errorf("failed to unlock developer account: %v", err)
}
log.Info("Using developer account", "address", developer.Address)
// get developer mode chain config
c.chain = chains.GetDeveloperChain(c.Developer.Period, developer.Address)
// update the parameters
n.NetworkId = c.chain.NetworkId
n.Genesis = c.chain.Genesis
// Update cache
c.Cache.Cache = 1024
// Update sync mode
c.SyncMode = "full"
// update miner gas price
if n.Miner.GasPrice == nil {
n.Miner.GasPrice = big.NewInt(1)
}
}
// discovery (this params should be in node.Config) // discovery (this params should be in node.Config)
{ {
n.EthDiscoveryURLs = c.P2P.Discovery.DNS n.EthDiscoveryURLs = c.P2P.Discovery.DNS
...@@ -777,17 +852,28 @@ func (c *Config) buildNode() (*node.Config, error) { ...@@ -777,17 +852,28 @@ func (c *Config) buildNode() (*node.Config, error) {
ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)), ListenAddr: c.P2P.Bind + ":" + strconv.Itoa(int(c.P2P.Port)),
DiscoveryV5: c.P2P.Discovery.V5Enabled, DiscoveryV5: c.P2P.Discovery.V5Enabled,
}, },
HTTPModules: c.JsonRPC.Modules, HTTPModules: c.JsonRPC.Http.Modules,
HTTPCors: c.JsonRPC.Cors, HTTPCors: c.JsonRPC.Cors,
HTTPVirtualHosts: c.JsonRPC.VHost, HTTPVirtualHosts: c.JsonRPC.VHost,
HTTPPathPrefix: c.JsonRPC.Http.Prefix, HTTPPathPrefix: c.JsonRPC.Http.Prefix,
WSModules: c.JsonRPC.Modules, WSModules: c.JsonRPC.Ws.Modules,
WSOrigins: c.JsonRPC.Cors, WSOrigins: c.JsonRPC.Cors,
WSPathPrefix: c.JsonRPC.Ws.Prefix, WSPathPrefix: c.JsonRPC.Ws.Prefix,
GraphQLCors: c.JsonRPC.Cors, GraphQLCors: c.JsonRPC.Cors,
GraphQLVirtualHosts: c.JsonRPC.VHost, GraphQLVirtualHosts: c.JsonRPC.VHost,
} }
// dev mode
if c.Developer.Enabled {
cfg.UseLightweightKDF = true
// disable p2p networking
c.P2P.NoDiscover = true
cfg.P2P.ListenAddr = ""
cfg.P2P.NoDial = true
cfg.P2P.DiscoveryV5 = false
}
// enable jsonrpc endpoints // enable jsonrpc endpoints
{ {
if c.JsonRPC.Http.Enabled { if c.JsonRPC.Http.Enabled {
...@@ -806,23 +892,26 @@ func (c *Config) buildNode() (*node.Config, error) { ...@@ -806,23 +892,26 @@ func (c *Config) buildNode() (*node.Config, error) {
} }
cfg.P2P.NAT = natif cfg.P2P.NAT = natif
// Discovery // only check for non-developer modes
// if no bootnodes are defined, use the ones from the chain file. if !c.Developer.Enabled {
bootnodes := c.P2P.Discovery.Bootnodes // Discovery
if len(bootnodes) == 0 { // if no bootnodes are defined, use the ones from the chain file.
bootnodes = c.chain.Bootnodes bootnodes := c.P2P.Discovery.Bootnodes
} if len(bootnodes) == 0 {
if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil { bootnodes = c.chain.Bootnodes
return nil, err }
} if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil {
if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil { return nil, err
return nil, err }
} if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil {
if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil { return nil, err
return nil, err }
} if cfg.P2P.StaticNodes, err = parseBootnodes(c.P2P.Discovery.StaticNodes); err != nil {
if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil { return nil, err
return nil, err }
if cfg.P2P.TrustedNodes, err = parseBootnodes(c.P2P.Discovery.TrustedNodes); err != nil {
return nil, err
}
} }
if c.P2P.NoDiscover { if c.P2P.NoDiscover {
......
...@@ -16,7 +16,7 @@ func TestConfigDefault(t *testing.T) { ...@@ -16,7 +16,7 @@ func TestConfigDefault(t *testing.T) {
_, err := config.buildNode() _, err := config.buildNode()
assert.NoError(t, err) assert.NoError(t, err)
_, err = config.buildEth() _, err = config.buildEth(nil)
assert.NoError(t, err) assert.NoError(t, err)
} }
......
...@@ -263,11 +263,6 @@ func (c *Command) Flags() *flagset.Flagset { ...@@ -263,11 +263,6 @@ func (c *Command) Flags() *flagset.Flagset {
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
Value: &c.cliConfig.JsonRPC.VHost, Value: &c.cliConfig.JsonRPC.VHost,
}) })
f.SliceStringFlag(&flagset.SliceStringFlag{
Name: "jsonrpc.modules",
Usage: "API's offered over the HTTP-RPC interface",
Value: &c.cliConfig.JsonRPC.Modules,
})
// http options // http options
f.BoolFlag(&flagset.BoolFlag{ f.BoolFlag(&flagset.BoolFlag{
...@@ -290,6 +285,12 @@ func (c *Command) Flags() *flagset.Flagset { ...@@ -290,6 +285,12 @@ func (c *Command) Flags() *flagset.Flagset {
Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.",
Value: &c.cliConfig.JsonRPC.Http.Prefix, Value: &c.cliConfig.JsonRPC.Http.Prefix,
}) })
f.SliceStringFlag(&flagset.SliceStringFlag{
Name: "http.modules",
Usage: "API's offered over the HTTP-RPC interface",
Value: &c.cliConfig.JsonRPC.Http.Modules,
})
// ws options // ws options
f.BoolFlag(&flagset.BoolFlag{ f.BoolFlag(&flagset.BoolFlag{
Name: "ws", Name: "ws",
...@@ -311,6 +312,12 @@ func (c *Command) Flags() *flagset.Flagset { ...@@ -311,6 +312,12 @@ func (c *Command) Flags() *flagset.Flagset {
Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.",
Value: &c.cliConfig.JsonRPC.Ws.Prefix, Value: &c.cliConfig.JsonRPC.Ws.Prefix,
}) })
f.SliceStringFlag(&flagset.SliceStringFlag{
Name: "ws.modules",
Usage: "API's offered over the WS-RPC interface",
Value: &c.cliConfig.JsonRPC.Ws.Modules,
})
// graphql options // graphql options
f.BoolFlag(&flagset.BoolFlag{ f.BoolFlag(&flagset.BoolFlag{
Name: "graphql", Name: "graphql",
...@@ -461,5 +468,17 @@ func (c *Command) Flags() *flagset.Flagset { ...@@ -461,5 +468,17 @@ func (c *Command) Flags() *flagset.Flagset {
Usage: "Address and port to bind the GRPC server", Usage: "Address and port to bind the GRPC server",
Value: &c.cliConfig.GRPC.Addr, Value: &c.cliConfig.GRPC.Addr,
}) })
// developer
f.BoolFlag(&flagset.BoolFlag{
Name: "dev",
Usage: "Enable developer mode with ephemeral proof-of-authority network and a pre-funded developer account, mining enabled",
Value: &c.cliConfig.Developer.Enabled,
})
f.Uint64Flag(&flagset.Uint64Flag{
Name: "dev.period",
Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
Value: &c.cliConfig.Developer.Period,
})
return f return f
} }
...@@ -69,11 +69,22 @@ func NewServer(config *Config) (*Server, error) { ...@@ -69,11 +69,22 @@ func NewServer(config *Config) (*Server, error) {
} }
srv.node = stack srv.node = stack
// setup account manager (only keystore)
{
keydir := stack.KeyStoreDir()
n, p := keystore.StandardScryptN, keystore.StandardScryptP
if config.Accounts.UseLightweightKDF {
n, p = keystore.LightScryptN, keystore.LightScryptP
}
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
}
// register the ethereum backend // register the ethereum backend
ethCfg, err := config.buildEth() ethCfg, err := config.buildEth(stack)
if err != nil { if err != nil {
return nil, err return nil, err
} }
backend, err := eth.New(stack, ethCfg) backend, err := eth.New(stack, ethCfg)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -85,7 +96,7 @@ func NewServer(config *Config) (*Server, error) { ...@@ -85,7 +96,7 @@ func NewServer(config *Config) (*Server, error) {
// graphql is started from another place // graphql is started from another place
if config.JsonRPC.Graphql.Enabled { if config.JsonRPC.Graphql.Enabled {
if err := graphql.New(stack, backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.Modules); err != nil { if err := graphql.New(stack, backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil {
return nil, fmt.Errorf("failed to register the GraphQL service: %v", err) return nil, fmt.Errorf("failed to register the GraphQL service: %v", err)
} }
} }
...@@ -97,18 +108,8 @@ func NewServer(config *Config) (*Server, error) { ...@@ -97,18 +108,8 @@ func NewServer(config *Config) (*Server, error) {
} }
} }
// setup account manager (only keystore) // sealing (if enabled) or in dev mode
{ if config.Sealer.Enabled || config.Developer.Enabled {
keydir := stack.KeyStoreDir()
n, p := keystore.StandardScryptN, keystore.StandardScryptP
if config.Accounts.UseLightweightKDF {
n, p = keystore.LightScryptN, keystore.LightScryptP
}
stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p))
}
// sealing (if enabled)
if config.Sealer.Enabled {
if err := backend.StartMining(1); err != nil { if err := backend.StartMining(1); err != nil {
return nil, err return nil, err
} }
......
package server
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestServer_DeveloperMode(t *testing.T) {
// get the default config
config := DefaultConfig()
// enable developer mode
config.Developer.Enabled = true
config.Developer.Period = 2 // block time
// start the server
server, err1 := NewServer(config)
if err1 != nil {
t.Fatalf("failed to start server: %v", err1)
}
// record the initial block number
blockNumber := server.backend.BlockChain().CurrentBlock().Header().Number.Int64()
var i int64 = 0
for i = 0; i < 10; i++ {
// We expect the node to mine blocks every `config.Developer.Period` time period
time.Sleep(time.Duration(config.Developer.Period) * time.Second)
currBlock := server.backend.BlockChain().CurrentBlock().Header().Number.Int64()
expected := blockNumber + i + 1
if res := assert.Equal(t, currBlock, expected); res == false {
break
}
}
// stop the server
server.Stop()
}