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 (
|
||||
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"
|
||||
)
|
||||
|
||||
|
@ -142,7 +142,7 @@ func TestHTTPAttachWelcome(t *testing.T) {
|
|||
|
||||
geth := runGeth(t,
|
||||
"--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
|
||||
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
|
||||
|
@ -160,7 +160,7 @@ func TestWSAttachWelcome(t *testing.T) {
|
|||
|
||||
geth := runGeth(t,
|
||||
"--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
|
||||
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("etherbase", func() string { return geth.Etherbase })
|
||||
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("apis", func() string { return apis })
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package console
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"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:]
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (c *Console) Welcome() {
|
||||
consensus := c.getConsensus()
|
||||
|
||||
// Print some generic Geth metadata
|
||||
fmt.Fprintf(c.printer, "Welcome to the Geth JavaScript console!\n\n")
|
||||
c.jsre.Run(`
|
||||
console.log("instance: " + web3.version.node);
|
||||
console.log("coinbase: " + eth.coinbase);
|
||||
console.log("at block: " + eth.blockNumber + " (" + new Date(1000 * eth.getBlock(eth.blockNumber).timestamp) + ")");
|
||||
console.log(" datadir: " + admin.datadir);
|
||||
`)
|
||||
console.log("instance: " + web3.version.node);
|
||||
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) + ")");
|
||||
`)
|
||||
}
|
||||
|
||||
c.jsre.Run(`
|
||||
console.log(" datadir: " + admin.datadir);
|
||||
`)
|
||||
|
||||
// List all the supported modules for the user to call
|
||||
if apis, err := c.client.SupportedModules(); err == nil {
|
||||
modules := make([]string, 0, len(apis))
|
||||
|
@ -294,6 +311,30 @@ func (c *Console) Welcome() {
|
|||
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
|
||||
// stream.
|
||||
func (c *Console) Evaluate(statement string) error {
|
||||
|
|
|
@ -28,6 +28,8 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/core"
|
||||
"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
|
||||
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
|
||||
Consensus string `json:"consensus"` // Consensus mechanism in use
|
||||
}
|
||||
|
||||
// NodeInfo retrieves some protocol metadata about the running host node.
|
||||
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
||||
currentBlock := pm.blockchain.CurrentBlock()
|
||||
|
||||
return &NodeInfo{
|
||||
Network: pm.networkID,
|
||||
Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
||||
Genesis: pm.blockchain.Genesis().Hash(),
|
||||
Config: pm.blockchain.Config(),
|
||||
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 {
|
||||
m := make(map[common.Address]consensus.Peer)
|
||||
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.
|
||||
func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
|
||||
func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
|
||||
|
|
|
@ -27,6 +27,11 @@ import (
|
|||
"sync"
|
||||
"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/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
@ -74,6 +79,58 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
|||
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,
|
||||
// with the given number of blocks already known, and potential notification
|
||||
// channels for different events. In case of an error, the constructor force-
|
||||
|
|
Loading…
Reference in New Issue