mirror of https://github.com/poanetwork/quorum.git
Bugfix/geth console displays incorrect block timestamp (#762)
Fix issue where geth console displays incorrect timestamp under Raft, due to Raft holding block timestamp in nanoseconds, instead of seconds.
This commit is contained in:
parent
9c0195fd57
commit
a9f96e0954
|
@ -33,7 +33,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
|
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
|
||||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
httpAPIs = "admin:1.0 eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||||
nodeKey = "b68c0338aa4b266bf38ebe84c6199ae9fac8b29f32998b3ed2fbeafebe8d65c9"
|
nodeKey = "b68c0338aa4b266bf38ebe84c6199ae9fac8b29f32998b3ed2fbeafebe8d65c9"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ func TestHTTPAttachWelcome(t *testing.T) {
|
||||||
|
|
||||||
geth := runGeth(t,
|
geth := runGeth(t,
|
||||||
"--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
"--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
"--etherbase", coinbase, "--rpc", "--rpcport", port)
|
"--etherbase", coinbase, "--rpc", "--rpcport", port, "--rpcapi", "admin,eth,net,web3")
|
||||||
|
|
||||||
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||||
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
|
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
|
||||||
|
@ -160,7 +160,7 @@ func TestWSAttachWelcome(t *testing.T) {
|
||||||
|
|
||||||
geth := runGeth(t,
|
geth := runGeth(t,
|
||||||
"--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
"--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
"--etherbase", coinbase, "--ws", "--wsport", port)
|
"--etherbase", coinbase, "--ws", "--wsport", port, "--wsapi", "admin,eth,net,web3")
|
||||||
|
|
||||||
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||||
testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs)
|
testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs)
|
||||||
|
@ -183,7 +183,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
||||||
attach.SetTemplateFunc("quorumver", func() string { return params.QuorumVersion })
|
attach.SetTemplateFunc("quorumver", func() string { return params.QuorumVersion })
|
||||||
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
||||||
attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
||||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") || strings.Contains(apis, "admin") })
|
||||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||||
attach.SetTemplateFunc("apis", func() string { return apis })
|
attach.SetTemplateFunc("apis", func() string { return apis })
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package console
|
package console
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -271,17 +272,33 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str
|
||||||
return line[:start], c.jsre.CompleteKeywords(line[start:pos]), line[pos:]
|
return line[:start], c.jsre.CompleteKeywords(line[start:pos]), line[pos:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Welcome show summary of current Geth instance and some metadata about the
|
// Welcome shows a summary of the current Geth instance and some metadata about the
|
||||||
// console's available modules.
|
// console's available modules.
|
||||||
func (c *Console) Welcome() {
|
func (c *Console) Welcome() {
|
||||||
|
consensus := c.getConsensus()
|
||||||
|
|
||||||
// Print some generic Geth metadata
|
// Print some generic Geth metadata
|
||||||
fmt.Fprintf(c.printer, "Welcome to the Geth JavaScript console!\n\n")
|
fmt.Fprintf(c.printer, "Welcome to the Geth JavaScript console!\n\n")
|
||||||
c.jsre.Run(`
|
c.jsre.Run(`
|
||||||
console.log("instance: " + web3.version.node);
|
console.log("instance: " + web3.version.node);
|
||||||
console.log("coinbase: " + eth.coinbase);
|
console.log("coinbase: " + eth.coinbase);
|
||||||
|
`)
|
||||||
|
|
||||||
|
// Quorum: Block timestamp for Raft is in nanoseconds, so convert accordingly
|
||||||
|
if consensus == "raft" {
|
||||||
|
c.jsre.Run(`
|
||||||
|
console.log("at block: " + eth.blockNumber + " (" + new Date(eth.getBlock(eth.blockNumber).timestamp / 1000000) + ")");
|
||||||
|
`)
|
||||||
|
} else {
|
||||||
|
c.jsre.Run(`
|
||||||
console.log("at block: " + eth.blockNumber + " (" + new Date(1000 * eth.getBlock(eth.blockNumber).timestamp) + ")");
|
console.log("at block: " + eth.blockNumber + " (" + new Date(1000 * eth.getBlock(eth.blockNumber).timestamp) + ")");
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.jsre.Run(`
|
||||||
console.log(" datadir: " + admin.datadir);
|
console.log(" datadir: " + admin.datadir);
|
||||||
`)
|
`)
|
||||||
|
|
||||||
// List all the supported modules for the user to call
|
// List all the supported modules for the user to call
|
||||||
if apis, err := c.client.SupportedModules(); err == nil {
|
if apis, err := c.client.SupportedModules(); err == nil {
|
||||||
modules := make([]string, 0, len(apis))
|
modules := make([]string, 0, len(apis))
|
||||||
|
@ -294,6 +311,30 @@ func (c *Console) Welcome() {
|
||||||
fmt.Fprintln(c.printer)
|
fmt.Fprintln(c.printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the consensus mechanism that is in use
|
||||||
|
func (c *Console) getConsensus() string {
|
||||||
|
|
||||||
|
var nodeInfo struct {
|
||||||
|
Protocols struct {
|
||||||
|
Eth struct { // only partial of eth/handler.go#NodeInfo
|
||||||
|
Consensus string
|
||||||
|
}
|
||||||
|
Istanbul struct { // a bit different from others
|
||||||
|
Consensus string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.client.CallContext(context.Background(), &nodeInfo, "admin_nodeInfo"); err != nil {
|
||||||
|
_, _ = fmt.Fprintf(c.printer, "WARNING: call to admin.getNodeInfo() failed, unable to determine consensus mechanism\n")
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
if nodeInfo.Protocols.Istanbul.Consensus != "" {
|
||||||
|
return nodeInfo.Protocols.Istanbul.Consensus
|
||||||
|
}
|
||||||
|
return nodeInfo.Protocols.Eth.Consensus
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluate executes code and pretty prints the result to the specified output
|
// Evaluate executes code and pretty prints the result to the specified output
|
||||||
// stream.
|
// stream.
|
||||||
func (c *Console) Evaluate(statement string) error {
|
func (c *Console) Evaluate(statement string) error {
|
||||||
|
|
|
@ -28,6 +28,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
@ -831,20 +833,42 @@ type NodeInfo struct {
|
||||||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||||
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
||||||
Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block
|
Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block
|
||||||
|
Consensus string `json:"consensus"` // Consensus mechanism in use
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfo retrieves some protocol metadata about the running host node.
|
// NodeInfo retrieves some protocol metadata about the running host node.
|
||||||
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
||||||
currentBlock := pm.blockchain.CurrentBlock()
|
currentBlock := pm.blockchain.CurrentBlock()
|
||||||
|
|
||||||
return &NodeInfo{
|
return &NodeInfo{
|
||||||
Network: pm.networkID,
|
Network: pm.networkID,
|
||||||
Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
||||||
Genesis: pm.blockchain.Genesis().Hash(),
|
Genesis: pm.blockchain.Genesis().Hash(),
|
||||||
Config: pm.blockchain.Config(),
|
Config: pm.blockchain.Config(),
|
||||||
Head: currentBlock.Hash(),
|
Head: currentBlock.Hash(),
|
||||||
|
Consensus: pm.getConsensusAlgorithm(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pm *ProtocolManager) getConsensusAlgorithm() string {
|
||||||
|
var consensusAlgo string
|
||||||
|
if pm.raftMode { // raft does not use consensus interface
|
||||||
|
consensusAlgo = "raft"
|
||||||
|
} else {
|
||||||
|
switch pm.engine.(type) {
|
||||||
|
case consensus.Istanbul:
|
||||||
|
consensusAlgo = "istanbul"
|
||||||
|
case *clique.Clique:
|
||||||
|
consensusAlgo = "clique"
|
||||||
|
case *ethash.Ethash:
|
||||||
|
consensusAlgo = "ethash"
|
||||||
|
default:
|
||||||
|
consensusAlgo = "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consensusAlgo
|
||||||
|
}
|
||||||
|
|
||||||
func (self *ProtocolManager) FindPeers(targets map[common.Address]bool) map[common.Address]consensus.Peer {
|
func (self *ProtocolManager) FindPeers(targets map[common.Address]bool) map[common.Address]consensus.Peer {
|
||||||
m := make(map[common.Address]consensus.Peer)
|
m := make(map[common.Address]consensus.Peer)
|
||||||
for _, p := range self.peers.Peers() {
|
for _, p := range self.peers.Peers() {
|
||||||
|
|
|
@ -70,6 +70,45 @@ func TestProtocolCompatibility(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that correct consensus mechanism details are returned in NodeInfo.
|
||||||
|
func TestNodeInfo(t *testing.T) {
|
||||||
|
|
||||||
|
// Define the tests to be run
|
||||||
|
tests := []struct {
|
||||||
|
consensus string
|
||||||
|
cliqueConfig *params.CliqueConfig
|
||||||
|
istanbulConfig *params.IstanbulConfig
|
||||||
|
raftMode bool
|
||||||
|
}{
|
||||||
|
{"ethash", nil, nil, false},
|
||||||
|
{"raft", nil, nil, true},
|
||||||
|
{"istanbul", nil, ¶ms.IstanbulConfig{1, 1}, false},
|
||||||
|
{"clique", ¶ms.CliqueConfig{1, 1}, nil, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure anything we screw up is restored
|
||||||
|
backup := consensus.EthProtocol.Versions
|
||||||
|
defer func() { consensus.EthProtocol.Versions = backup }()
|
||||||
|
|
||||||
|
// Try all available consensus mechanisms and check for errors
|
||||||
|
for i, tt := range tests {
|
||||||
|
|
||||||
|
pm, _, err := newTestProtocolManagerConsensus(tt.consensus, tt.cliqueConfig, tt.istanbulConfig, tt.raftMode)
|
||||||
|
|
||||||
|
if pm != nil {
|
||||||
|
defer pm.Stop()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
pmConsensus := pm.getConsensusAlgorithm()
|
||||||
|
if tt.consensus != pmConsensus {
|
||||||
|
t.Errorf("test %d: consensus type error, wanted %v but got %v", i, tt.consensus, pmConsensus)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf("test %d: consensus type error %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that block headers can be retrieved from a remote chain based on user queries.
|
// Tests that block headers can be retrieved from a remote chain based on user queries.
|
||||||
func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
|
func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
|
||||||
func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
|
func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
|
||||||
|
|
|
@ -27,6 +27,11 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/istanbul"
|
||||||
|
istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
@ -74,6 +79,58 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
||||||
return pm, db, nil
|
return pm, db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newTestProtocolManagerConsensus creates a new protocol manager for testing purposes,
|
||||||
|
// that uses the specified consensus mechanism.
|
||||||
|
func newTestProtocolManagerConsensus(consensusAlgo string, cliqueConfig *params.CliqueConfig, istanbulConfig *params.IstanbulConfig, raftMode bool) (*ProtocolManager, *ethdb.MemDatabase, error) {
|
||||||
|
|
||||||
|
config := params.QuorumTestChainConfig
|
||||||
|
config.Clique = cliqueConfig
|
||||||
|
config.Istanbul = istanbulConfig
|
||||||
|
|
||||||
|
var (
|
||||||
|
blocks = 0
|
||||||
|
evmux = new(event.TypeMux)
|
||||||
|
engine consensus.Engine = ethash.NewFaker()
|
||||||
|
db = ethdb.NewMemDatabase()
|
||||||
|
gspec = &core.Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
||||||
|
}
|
||||||
|
genesis = gspec.MustCommit(db)
|
||||||
|
blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
||||||
|
)
|
||||||
|
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, nil)
|
||||||
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch consensusAlgo {
|
||||||
|
case "raft":
|
||||||
|
engine = ethash.NewFaker() //raft doesn't use engine, but just mirroring what runtime code does
|
||||||
|
|
||||||
|
case "istanbul":
|
||||||
|
var istanbul istanbul.Config
|
||||||
|
config.Istanbul.Epoch = istanbulConfig.Epoch
|
||||||
|
config.Istanbul.ProposerPolicy = istanbulConfig.ProposerPolicy
|
||||||
|
|
||||||
|
nodeKey, _ := crypto.GenerateKey()
|
||||||
|
engine = istanbulBackend.New(&istanbul, nodeKey, db)
|
||||||
|
|
||||||
|
case "clique":
|
||||||
|
engine = clique.New(config.Clique, db)
|
||||||
|
|
||||||
|
default:
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
}
|
||||||
|
|
||||||
|
pm, err := NewProtocolManager(config, 61, DefaultConfig.NetworkId, evmux, &testTxPool{added: nil}, engine, blockchain, db, raftMode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
pm.Start(1000)
|
||||||
|
return pm, db, nil
|
||||||
|
}
|
||||||
|
|
||||||
// newTestProtocolManagerMust creates a new protocol manager for testing purposes,
|
// newTestProtocolManagerMust creates a new protocol manager for testing purposes,
|
||||||
// with the given number of blocks already known, and potential notification
|
// with the given number of blocks already known, and potential notification
|
||||||
// channels for different events. In case of an error, the constructor force-
|
// channels for different events. In case of an error, the constructor force-
|
||||||
|
|
Loading…
Reference in New Issue