diff --git a/hmy/api_backend.go b/hmy/api_backend.go index eea27177d..24cdc69ff 100644 --- a/hmy/api_backend.go +++ b/hmy/api_backend.go @@ -228,3 +228,8 @@ func (b *APIBackend) GetEVM(ctx context.Context, msg core.Message, state *state. func (b *APIBackend) RPCGasCap() *big.Int { return b.hmy.RPCGasCap // TODO(ricl): should be hmy.config.RPCGasCap } + +// GetShardID returns the gas cap of rpc +func (b *APIBackend) GetShardID() uint32 { + return b.hmy.shardID +} diff --git a/hmy/backend.go b/hmy/backend.go index 9aca3ebee..c6a933b61 100644 --- a/hmy/backend.go +++ b/hmy/backend.go @@ -37,6 +37,7 @@ type Harmony struct { // TODO(ricl): this is never set. Will result in nil pointer bug // RPCGasCap is the global gas cap for eth-call variants. RPCGasCap *big.Int `toml:",omitempty"` + shardID uint32 } // NodeAPI is the list of functions from node used to call rpc apis. @@ -50,7 +51,7 @@ type NodeAPI interface { // New creates a new Harmony object (including the // initialisation of the common Harmony object) -func New(nodeAPI NodeAPI, txPool *core.TxPool, eventMux *event.TypeMux) (*Harmony, error) { +func New(nodeAPI NodeAPI, txPool *core.TxPool, eventMux *event.TypeMux, shardID uint32) (*Harmony, error) { chainDb := nodeAPI.Blockchain().ChainDB() hmy := &Harmony{ shutdownChan: make(chan bool), @@ -63,6 +64,7 @@ func New(nodeAPI NodeAPI, txPool *core.TxPool, eventMux *event.TypeMux) (*Harmon bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), nodeAPI: nodeAPI, networkID: 1, // TODO(ricl): this should be from config + shardID: shardID, } hmy.APIBackend = &APIBackend{hmy} diff --git a/internal/common/address_test.go b/internal/common/address_test.go index 2790a88c1..96675916a 100644 --- a/internal/common/address_test.go +++ b/internal/common/address_test.go @@ -150,6 +150,19 @@ func TestAddressToBech32(t *testing.T) { } } +func TestParseAddr(t *testing.T) { + adr := ethCommon.HexToAddress("0x15a128e599b74842bccba860311efa92991bffb5") + adr2 := ParseAddr("one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur") + if adr.Hex() != adr2.Hex() { + t.Errorf("error on ParseAddr") + } + // Parsing incorrect address + adr3 := ParseAddr("helloworldone1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ufdfsrfasdfadfas") + if adr3.Hex() != "0x0000000000000000000000000000000000000000" { + t.Errorf("error on ParseAddr") + } +} + func TestAddress_Scan(t *testing.T) { type args struct { src interface{} diff --git a/internal/configs/sharding/fixedschedule.go b/internal/configs/sharding/fixedschedule.go index 8d20fde35..44befcd89 100644 --- a/internal/configs/sharding/fixedschedule.go +++ b/internal/configs/sharding/fixedschedule.go @@ -90,6 +90,11 @@ func (s fixedSchedule) GetNetworkID() NetworkID { return DevNet } +// GetShardingStructure is the sharding structure for fixed schedule. +func (fixedSchedule) GetShardingStructure(numShard, shardID int) []map[string]interface{} { + return genShardingStructure(numShard, shardID, TestNetHTTPPattern, TestNetHTTPPattern) +} + // NewFixedSchedule returns a sharding configuration schedule that uses the // given config instance for all epochs. Useful for testing. func NewFixedSchedule(instance Instance) Schedule { diff --git a/internal/configs/sharding/instance.go b/internal/configs/sharding/instance.go index 66ed94844..db387d7f9 100644 --- a/internal/configs/sharding/instance.go +++ b/internal/configs/sharding/instance.go @@ -10,7 +10,7 @@ import ( // NetworkID is the network type of the blockchain. type NetworkID byte -//Consensus and other message categories +// Constants for NetworkID. const ( MainNet NetworkID = iota TestNet diff --git a/internal/configs/sharding/localnet.go b/internal/configs/sharding/localnet.go index 05b0fbec8..5985dfd2c 100644 --- a/internal/configs/sharding/localnet.go +++ b/internal/configs/sharding/localnet.go @@ -1,6 +1,7 @@ package shardingconfig import ( + "fmt" "math/big" "time" @@ -32,6 +33,11 @@ const ( localnetMaxTxPoolSizeLimit = 8000 localnetMaxNumTxsPerBlockLimit = 1000 localnetRecentTxDuration = time.Hour + + // LocalNetHTTPPattern is the http pattern for mainnet. + LocalNetHTTPPattern = "http://s%d.t.hmny.io:9500" + // LocalNetWSPattern is the websocket pattern for mainnet. + LocalNetWSPattern = "ws://s%d.t.hmny.io:9800" ) func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -126,6 +132,20 @@ func (ls localnetSchedule) GetNetworkID() NetworkID { return LocalNet } +// GetShardingStructure is the sharding structure for localnet. +func (ls localnetSchedule) GetShardingStructure(numShard, shardID int) []map[string]interface{} { + res := []map[string]interface{}{} + for i := 0; i < numShard; i++ { + res = append(res, map[string]interface{}{ + "current": int(shardID) == i, + "shardID": i, + "http": fmt.Sprintf("http://127.0.0.1:%d", 9500+i), + "ws": fmt.Sprintf("ws://127.0.0.1:%d", 9800+i), + }) + } + return res +} + var localnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(localnetV1Epoch), big.NewInt(localnetV2Epoch)} var localnetV0 = MustNewInstance(2, 7, 5, genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch) diff --git a/internal/configs/sharding/mainnet.go b/internal/configs/sharding/mainnet.go index a5f3d3d65..d077b8a5b 100644 --- a/internal/configs/sharding/mainnet.go +++ b/internal/configs/sharding/mainnet.go @@ -33,6 +33,11 @@ const ( mainnetMaxTxPoolSizeLimit = 8000 mainnetMaxNumTxsPerBlockLimit = 1000 mainnetRecentTxDuration = time.Hour + + // MainNetHTTPPattern is the http pattern for mainnet. + MainNetHTTPPattern = "http://s%d.t.hmny.io:9500" + // MainNetWSPattern is the websocket pattern for mainnet. + MainNetWSPattern = "ws://s%d.t.hmny.io:9800" ) // MainnetSchedule is the mainnet sharding configuration schedule. @@ -149,6 +154,11 @@ func (ms mainnetSchedule) GetNetworkID() NetworkID { return MainNet } +// GetShardingStructure is the sharding structure for mainnet. +func (ms mainnetSchedule) GetShardingStructure(numShard, shardID int) []map[string]interface{} { + return genShardingStructure(numShard, shardID, MainNetHTTPPattern, MainNetWSPattern) +} + var mainnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(mainnetV0_1Epoch), big.NewInt(mainnetV0_2Epoch), big.NewInt(mainnetV0_3Epoch), big.NewInt(mainnetV0_4Epoch), big.NewInt(mainnetV1Epoch), big.NewInt(mainnetV1_1Epoch), big.NewInt(mainnetV1_2Epoch)} var mainnetV0 = MustNewInstance(4, 150, 112, genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, mainnetReshardingEpoch) diff --git a/internal/configs/sharding/pangaea.go b/internal/configs/sharding/pangaea.go index 68cb11a90..5be9831f3 100644 --- a/internal/configs/sharding/pangaea.go +++ b/internal/configs/sharding/pangaea.go @@ -10,6 +10,13 @@ import ( "github.com/harmony-one/harmony/internal/genesis" ) +const ( + // PangaeaHTTPPattern is the http pattern for pangaea. + PangaeaHTTPPattern = "http://s%d.pga.hmny.io:9500" + // PangaeaWSPattern is the websocket pattern for pangaea. + PangaeaWSPattern = "ws://s%d.pga.hmny.io:9800" +) + // PangaeaSchedule is the Pangaea sharding configuration schedule. var PangaeaSchedule pangaeaSchedule @@ -89,3 +96,8 @@ func (ps pangaeaSchedule) TxsThrottleConfig() *TxsThrottleConfig { func (pangaeaSchedule) GetNetworkID() NetworkID { return Pangaea } + +// GetShardingStructure is the sharding structure for mainnet. +func (pangaeaSchedule) GetShardingStructure(numShard, shardID int) []map[string]interface{} { + return genShardingStructure(numShard, shardID, PangaeaHTTPPattern, PangaeaWSPattern) +} diff --git a/internal/configs/sharding/shardingconfig.go b/internal/configs/sharding/shardingconfig.go index 25fded6a3..56fa55d96 100644 --- a/internal/configs/sharding/shardingconfig.go +++ b/internal/configs/sharding/shardingconfig.go @@ -3,6 +3,7 @@ package shardingconfig import ( + "fmt" "math/big" "time" @@ -56,6 +57,9 @@ type Schedule interface { // GetNetworkID() return networkID type. GetNetworkID() NetworkID + + // GetShardingStructure returns sharding structure. + GetShardingStructure(int, int) []map[string]interface{} } // Instance is one sharding configuration instance. @@ -124,3 +128,17 @@ type TxsThrottleConfig struct { // Max total number of transactions allowed to be processed per block MaxNumTxsPerBlockLimit int } + +// genShardingStructure return sharding structure, given shard number and its patterns. +func genShardingStructure(shardNum, shardID int, httpPattern, wsPattern string) []map[string]interface{} { + res := []map[string]interface{}{} + for i := 0; i < shardNum; i++ { + res = append(res, map[string]interface{}{ + "current": int(shardID) == i, + "shardID": i, + "http": fmt.Sprintf(httpPattern, i), + "ws": fmt.Sprintf(wsPattern, i), + }) + } + return res +} diff --git a/internal/configs/sharding/shardingconfig_test.go b/internal/configs/sharding/shardingconfig_test.go index 29f322e6d..ef02c5c20 100644 --- a/internal/configs/sharding/shardingconfig_test.go +++ b/internal/configs/sharding/shardingconfig_test.go @@ -1,6 +1,7 @@ package shardingconfig import ( + "fmt" "math/big" "testing" ) @@ -86,3 +87,26 @@ func TestCalcEpochNumber(t *testing.T) { } } } + +func TestGetShardingStructure(t *testing.T) { + shardID := 0 + numShard := 4 + res := genShardingStructure(numShard, shardID, "http://s%d.t.hmy.io:9500", "ws://s%d.t.hmy.io:9800") + if len(res) != 4 || !res[0]["current"].(bool) || res[1]["current"].(bool) || res[2]["current"].(bool) || res[3]["current"].(bool) { + t.Error("Error when generating sharding structure") + } + for i := 0; i < numShard; i++ { + if res[i]["current"].(bool) != (i == shardID) { + t.Error("Error when generating sharding structure") + } + if res[i]["shardID"].(int) != i { + t.Error("Error when generating sharding structure") + } + if res[i]["http"].(string) != fmt.Sprintf("http://s%d.t.hmy.io:9500", i) { + t.Error("Error when generating sharding structure") + } + if res[i]["ws"].(string) != fmt.Sprintf("ws://s%d.t.hmy.io:9800", i) { + t.Error("Error when generating sharding structure") + } + } +} diff --git a/internal/configs/sharding/testnet.go b/internal/configs/sharding/testnet.go index 57d159630..f2b05bd05 100644 --- a/internal/configs/sharding/testnet.go +++ b/internal/configs/sharding/testnet.go @@ -30,6 +30,11 @@ const ( testnetMaxTxPoolSizeLimit = 8000 testnetMaxNumTxsPerBlockLimit = 1000 testnetRecentTxDuration = time.Hour + + // TestNetHTTPPattern is the http pattern for testnet. + TestNetHTTPPattern = "http://s%d.b.hmny.io:9500" + // TestNetWSPattern is the websocket pattern for testnet. + TestNetWSPattern = "ws://s%d.s.hmny.io:9800" ) func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance { @@ -125,6 +130,11 @@ func (ts testnetSchedule) GetNetworkID() NetworkID { return TestNet } +// GetShardingStructure is the sharding structure for testnet. +func (ts testnetSchedule) GetShardingStructure(numShard, shardID int) []map[string]interface{} { + return genShardingStructure(numShard, shardID, TestNetHTTPPattern, TestNetWSPattern) +} + var testnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(testnetV1Epoch), big.NewInt(testnetV2Epoch)} var testnetV0 = MustNewInstance(2, 150, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch) diff --git a/internal/hmyapi/backend.go b/internal/hmyapi/backend.go index dad963882..d6adb727d 100644 --- a/internal/hmyapi/backend.go +++ b/internal/hmyapi/backend.go @@ -63,6 +63,7 @@ type Backend interface { CurrentBlock() *types.Block // Get balance GetBalance(address common.Address) (*hexutil.Big, error) + GetShardID() uint32 } // GetAPIs returns all the APIs. diff --git a/internal/hmyapi/blockchain.go b/internal/hmyapi/blockchain.go index e79fba2c0..359672536 100644 --- a/internal/hmyapi/blockchain.go +++ b/internal/hmyapi/blockchain.go @@ -63,6 +63,16 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash comm return nil, err } +// GetShardingStructure returns an array of sharding structures. +func (s *PublicBlockChainAPI) GetShardingStructure(ctx context.Context) ([]map[string]interface{}, error) { + // Get header and number of shards. + header := s.b.CurrentBlock().Header() + numShard := core.ShardingSchedule.InstanceForEpoch(header.Epoch()).NumShards() + + // Return shareding structure for each case. + return core.ShardingSchedule.GetShardingStructure(int(numShard), int(s.b.GetShardID())), nil +} + // GetCode returns the code stored at the given address in the state for the given block number. func (s *PublicBlockChainAPI) GetCode(ctx context.Context, addr string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { address := internal_common.ParseAddr(addr) diff --git a/node/rpc.go b/node/rpc.go index 5d3cf96e8..c5c593386 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -46,7 +46,7 @@ var ( // StartRPC start RPC service func (node *Node) StartRPC(nodePort string) error { // Gather all the possible APIs to surface - harmony, _ = hmy.New(node, node.TxPool, new(event.TypeMux)) + harmony, _ = hmy.New(node, node.TxPool, new(event.TypeMux), node.Consensus.ShardID) apis := node.APIs()