Node API Refactor - pt3 (Stage 3.1 of Node API Overhaul) (#3297)

* [rosetta] Add server with example block & network services

* Update go.mod for rosetta SDK

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [internal/configs] Add RosettaServer to node config

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Add rosetta port flag

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [node] Add rosetta server start & rename api.go

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Change server start to use nodeconfig of rosetta

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Cleanup debugging prints

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Fix stdout print & document placeholders

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Fix lint & make StartSevers more consistent

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Disable rosetta by default

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [test] Make explorer deploy rosetta server

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Use direct http server for start

* Make go.mod changes minimal

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Fix fmt

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Fix fmt of go.mod

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [rosetta] Use port 9700 instead of 10000

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Bump config version

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Add v1.0.0 config backwards compatibility test

* Included update message if old config is loaded

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [test] Do not broadcast invalid tx on localnet

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Correct for invalid port when loading old config

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>

* [cmd] Make rosetta variable names consistent

Signed-off-by: Daniel Van Der Maden <dvandermaden0@berkeley.edu>
pull/3303/head
Daniel Van Der Maden 4 years ago committed by GitHub
parent 03bf274048
commit 8068d80200
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      cmd/harmony/config.go
  2. 80
      cmd/harmony/config_test.go
  3. 10
      cmd/harmony/default.go
  4. 28
      cmd/harmony/flags.go
  5. 52
      cmd/harmony/flags_test.go
  6. 18
      cmd/harmony/main.go
  7. 7
      go.mod
  8. 26
      internal/configs/node/config.go
  9. 14
      internal/configs/node/network.go
  10. 7
      node/api.go
  11. 75
      rosetta/common/config.go
  12. 87
      rosetta/rosetta.go
  13. 158
      rosetta/services/block_service.go
  14. 100
      rosetta/services/network_service.go
  15. 4
      test/deploy.sh

@ -97,9 +97,11 @@ type logContext struct {
}
type httpConfig struct {
Enabled bool
IP string
Port int
Enabled bool
IP string
Port int
RosettaEnabled bool
RosettaPort int
}
type wsConfig struct {
@ -235,6 +237,11 @@ func loadHarmonyConfig(file string) (harmonyConfig, error) {
if err := toml.Unmarshal(b, &config); err != nil {
return harmonyConfig{}, err
}
// Correct for old config version load (port 0 is invalid anyways)
if config.HTTP.RosettaPort == 0 {
config.HTTP.RosettaPort = defaultConfig.HTTP.RosettaPort
}
return config, nil
}

@ -2,6 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
@ -28,6 +29,85 @@ func init() {
}
}
func TestV1_0_0Config(t *testing.T) {
testConfig := `Version = "1.0.0"
[BLSKeys]
KMSConfigFile = ""
KMSConfigSrcType = "shared"
KMSEnabled = true
KeyDir = "./.hmy/blskeys"
KeyFiles = []
MaxKeys = 10
PassEnabled = true
PassFile = ""
PassSrcType = "auto"
SavePassphrase = false
[General]
DataDir = "./"
IsArchival = false
NoStaking = false
NodeType = "validator"
ShardID = -1
[HTTP]
Enabled = true
IP = "127.0.0.1"
Port = 9500
[Log]
FileName = "harmony.log"
Folder = "./latest"
RotateSize = 100
Verbosity = 3
[Network]
BootNodes = ["/ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv","/ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9","/ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX","/ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj"]
DNSPort = 9000
DNSZone = "t.hmny.io"
LegacySyncing = false
NetworkType = "mainnet"
[P2P]
KeyFile = "./.hmykey"
Port = 9000
[Pprof]
Enabled = false
ListenAddr = "127.0.0.1:6060"
[TxPool]
BlacklistFile = "./.hmy/blacklist.txt"
[WS]
Enabled = true
IP = "127.0.0.1"
Port = 9800`
testDir := filepath.Join(testBaseDir, t.Name())
os.RemoveAll(testDir)
os.MkdirAll(testDir, 0777)
file := filepath.Join(testDir, "test.config")
err := ioutil.WriteFile(file, []byte(testConfig), 0644)
if err != nil {
t.Fatal(err)
}
config, err := loadHarmonyConfig(file)
if err != nil {
t.Fatal(err)
}
if config.HTTP.RosettaEnabled {
t.Errorf("Expected rosetta http server to be disabled when loading old config")
}
if config.Version != "1.0.0" {
t.Errorf("Expected config version: 1.0.0, not %v", config.Version)
}
config.Version = defaultConfig.Version // Shortcut for testing, value checked above
if !reflect.DeepEqual(config, defaultConfig) {
t.Errorf("Unexpected config \n\t%+v \n\t%+v", config, defaultConfig)
}
}
func TestPersistConfig(t *testing.T) {
testDir := filepath.Join(testBaseDir, t.Name())
os.RemoveAll(testDir)

@ -2,7 +2,7 @@ package main
import nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
const tomlConfigVersion = "1.0.0"
const tomlConfigVersion = "1.0.1"
const (
defNetworkType = nodeconfig.Mainnet
@ -23,9 +23,11 @@ var defaultConfig = harmonyConfig{
KeyFile: "./.hmykey",
},
HTTP: httpConfig{
Enabled: true,
IP: "127.0.0.1",
Port: nodeconfig.DefaultRPCPort,
Enabled: true,
RosettaEnabled: false,
IP: "127.0.0.1",
Port: nodeconfig.DefaultRPCPort,
RosettaPort: nodeconfig.DefaultRosettaPort,
},
WS: wsConfig{
Enabled: true,

@ -45,8 +45,10 @@ var (
httpFlags = []cli.Flag{
httpEnabledFlag,
httpRosettaEnabledFlag,
httpIPFlag,
httpPortFlag,
httpRosettaPortFlag,
}
wsFlags = []cli.Flag{
@ -396,10 +398,20 @@ var (
Usage: "rpc port to listen for HTTP requests",
DefValue: defaultConfig.HTTP.Port,
}
httpRosettaEnabledFlag = cli.BoolFlag{
Name: "http.rosetta",
Usage: "enable HTTP / Rosetta requests",
DefValue: defaultConfig.HTTP.RosettaEnabled,
}
httpRosettaPortFlag = cli.IntFlag{
Name: "http.rosetta.port",
Usage: "rosetta port to listen for HTTP requests",
DefValue: defaultConfig.HTTP.RosettaPort,
}
)
func applyHTTPFlags(cmd *cobra.Command, config *harmonyConfig) {
var isRPCSpecified bool
var isRPCSpecified, isRosettaSpecified bool
if cli.IsFlagChanged(cmd, httpIPFlag) {
config.HTTP.IP = cli.GetStringFlagValue(cmd, httpIPFlag)
@ -411,6 +423,17 @@ func applyHTTPFlags(cmd *cobra.Command, config *harmonyConfig) {
isRPCSpecified = true
}
if cli.IsFlagChanged(cmd, httpRosettaPortFlag) {
config.HTTP.RosettaPort = cli.GetIntFlagValue(cmd, httpRosettaPortFlag)
isRosettaSpecified = true
}
if cli.IsFlagChanged(cmd, httpRosettaEnabledFlag) {
config.HTTP.RosettaEnabled = cli.GetBoolFlagValue(cmd, httpRosettaEnabledFlag)
} else if isRosettaSpecified {
config.HTTP.RosettaEnabled = true
}
if cli.IsFlagChanged(cmd, httpEnabledFlag) {
config.HTTP.Enabled = cli.GetBoolFlagValue(cmd, httpEnabledFlag)
} else if isRPCSpecified {
@ -1028,7 +1051,8 @@ func applyLegacyMiscFlags(cmd *cobra.Command, config *harmonyConfig) {
if cli.IsFlagChanged(cmd, legacyPortFlag) {
legacyPort := cli.GetIntFlagValue(cmd, legacyPortFlag)
config.P2P.Port = legacyPort
config.HTTP.Port = nodeconfig.GetHTTPPortFromBase(legacyPort)
config.HTTP.Port = nodeconfig.GetRPCHTTPPortFromBase(legacyPort)
config.HTTP.RosettaPort = nodeconfig.GetRosettaHTTPPortFromBase(legacyPort)
config.WS.Port = nodeconfig.GetWSPortFromBase(legacyPort)
}

@ -54,9 +54,11 @@ func TestHarmonyFlags(t *testing.T) {
KeyFile: defaultConfig.P2P.KeyFile,
},
HTTP: httpConfig{
Enabled: true,
IP: "127.0.0.1",
Port: 9500,
Enabled: true,
IP: "127.0.0.1",
Port: 9500,
RosettaEnabled: false,
RosettaPort: 9700,
},
WS: wsConfig{
Enabled: true,
@ -324,25 +326,51 @@ func TestRPCFlags(t *testing.T) {
{
args: []string{"--http=false"},
expConfig: httpConfig{
Enabled: false,
IP: defaultConfig.HTTP.IP,
Port: defaultConfig.HTTP.Port,
Enabled: false,
RosettaEnabled: false,
IP: defaultConfig.HTTP.IP,
Port: defaultConfig.HTTP.Port,
RosettaPort: defaultConfig.HTTP.RosettaPort,
},
},
{
args: []string{"--http.ip", "8.8.8.8", "--http.port", "9001"},
expConfig: httpConfig{
Enabled: true,
IP: "8.8.8.8",
Port: 9001,
Enabled: true,
RosettaEnabled: false,
IP: "8.8.8.8",
Port: 9001,
RosettaPort: defaultConfig.HTTP.RosettaPort,
},
},
{
args: []string{"--http.ip", "8.8.8.8", "--http.port", "9001", "--http.rosetta.port", "10001"},
expConfig: httpConfig{
Enabled: true,
RosettaEnabled: true,
IP: "8.8.8.8",
Port: 9001,
RosettaPort: 10001,
},
},
{
args: []string{"--http.ip", "8.8.8.8", "--http.rosetta.port", "10001"},
expConfig: httpConfig{
Enabled: true,
RosettaEnabled: true,
IP: "8.8.8.8",
Port: defaultConfig.HTTP.Port,
RosettaPort: 10001,
},
},
{
args: []string{"--ip", "8.8.8.8", "--port", "9001", "--public_rpc"},
expConfig: httpConfig{
Enabled: true,
IP: publicListenIP,
Port: 9501,
Enabled: true,
RosettaEnabled: false,
IP: publicListenIP,
Port: 9501,
RosettaPort: 9701,
},
},
}

@ -148,6 +148,11 @@ func getHarmonyConfig(cmd *cobra.Command) (harmonyConfig, error) {
if err != nil {
return harmonyConfig{}, err
}
if config.Version != defaultConfig.Version {
fmt.Printf("Loaded config version %s which is not latest (%s).\n",
config.Version, defaultConfig.Version)
fmt.Println("Update saved config with `./harmony dumpconfig [config_file]`")
}
applyRootFlags(cmd, &config)
@ -279,6 +284,13 @@ func setupNodeAndRun(hc harmonyConfig) {
currentNode.SupportBeaconSyncing()
}
// Parse rosetta config
nodeConfig.RosettaServer = nodeconfig.RosettaServerConfig{
HTTPEnabled: hc.HTTP.RosettaEnabled,
HTTPIp: hc.HTTP.IP,
HTTPPort: hc.HTTP.RosettaPort,
}
if hc.Revert != nil && hc.Revert.RevertBefore != 0 && hc.Revert.RevertTo != 0 {
chain := currentNode.Blockchain()
if hc.Revert.RevertBeacon {
@ -327,6 +339,12 @@ func setupNodeAndRun(hc harmonyConfig) {
Msg("StartRPC failed")
}
if err := currentNode.StartRosetta(); err != nil {
utils.Logger().Warn().
Err(err).
Msg("Start Rosetta failed")
}
if err := currentNode.BootstrapConsensus(); err != nil {
fmt.Println("could not bootstrap consensus", err.Error())
os.Exit(-1)

@ -10,18 +10,19 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/cespare/cp v1.1.1
github.com/coinbase/rosetta-sdk-go v0.3.4
github.com/davecgh/go-spew v1.1.1
github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f // indirect
github.com/deckarep/golang-set v1.7.1
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.8.27
github.com/ethereum/go-ethereum v1.9.18
github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a // indirect
github.com/garslo/gogen v0.0.0-20170307003452-d6ebae628c7c // indirect
github.com/golang/mock v1.4.0
github.com/golang/protobuf v1.4.0
github.com/golangci/golangci-lint v1.22.2
github.com/gorilla/handlers v1.4.0 // indirect
github.com/gorilla/mux v1.7.2
github.com/gorilla/mux v1.7.4
github.com/gorilla/websocket v1.4.2
github.com/harmony-ek/gencodec v0.0.0-20190215044613-e6740dbdd846
github.com/harmony-one/abool v1.0.1
@ -78,3 +79,5 @@ require (
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
gopkg.in/yaml.v2 v2.2.7
)
replace github.com/ethereum/go-ethereum => github.com/ethereum/go-ethereum v1.8.27

@ -68,15 +68,16 @@ var peerID peer.ID // PeerID of the node
// ConfigType is the structure of all node related configuration variables
type ConfigType struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
beacon GroupID // the beacon group ID
group GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet
ShardID uint32 // ShardID of this node; TODO ek – revisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
RPCServer RPCServerConfig // RPC server port and ip
beacon GroupID // the beacon group ID
group GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet
ShardID uint32 // ShardID of this node; TODO ek – revisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
RPCServer RPCServerConfig // RPC server port and ip
RosettaServer RosettaServerConfig // rosetta server port and ip
StringRole string
P2PPriKey p2p_crypto.PrivKey
ConsensusPriKey multibls.PrivateKeys
@ -102,6 +103,13 @@ type RPCServerConfig struct {
WSPort int
}
// RosettaServerConfig is the config for the rosetta server
type RosettaServerConfig struct {
HTTPEnabled bool
HTTPIp string
HTTPPort int
}
// configs is a list of node configuration.
// It has at least one configuration.
// The first one is the default, global node configuration

@ -47,6 +47,8 @@ const (
DefaultDNSPort = 9000
// DefaultRPCPort is the default rpc port. The actual port used is 9000+500
DefaultRPCPort = 9500
// DefaultRosettaPort is the default rosetta port. The actual port used is 9000+700
DefaultRosettaPort = 9700
// DefaultWSPort is the default port for web socket endpoint. The actual port used is
DefaultWSPort = 9800
)
@ -55,6 +57,9 @@ const (
// rpcHTTPPortOffset is the port offset for RPC HTTP requests
rpcHTTPPortOffset = 500
// rpcHTTPPortOffset is the port offset for rosetta HTTP requests
rosettaHTTPPortOffset = 700
// rpcWSPortOffSet is the port offset for RPC websocket requests
rpcWSPortOffSet = 800
)
@ -100,11 +105,16 @@ func GetDefaultDNSPort(NetworkType) int {
return DefaultDNSPort
}
// GetHTTPPortFromBase return the HTTP port from base port
func GetHTTPPortFromBase(basePort int) int {
// GetRPCHTTPPortFromBase return the rpc HTTP port from base port
func GetRPCHTTPPortFromBase(basePort int) int {
return basePort + rpcHTTPPortOffset
}
// GetRosettaHTTPPortFromBase return the rosetta HTTP port from base port
func GetRosettaHTTPPortFromBase(basePort int) int {
return basePort + rosettaHTTPPortOffset
}
// GetWSPortFromBase return the Websocket port from the base port
func GetWSPortFromBase(basePort int) int {
return basePort + rpcWSPortOffSet

@ -4,6 +4,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/rosetta"
hmy_rpc "github.com/harmony-one/harmony/rpc"
"github.com/harmony-one/harmony/rpc/filters"
"github.com/libp2p/go-libp2p-core/peer"
@ -79,6 +80,12 @@ func (node *Node) StopRPC() error {
return hmy_rpc.StopServers()
}
// StartRosetta start rosetta service
func (node *Node) StartRosetta() error {
harmony := hmy.New(node, node.TxPool, node.CxPool, node.Consensus.ShardID)
return rosetta.StartServers(harmony, node.NodeConfig.RosettaServer)
}
// APIs return the collection of local RPC services.
// NOTE, some of these services probably need to be moved to somewhere else.
func (node *Node) APIs(harmony *hmy.Harmony) []rpc.API {

@ -0,0 +1,75 @@
package config
import (
"fmt"
"time"
"github.com/coinbase/rosetta-sdk-go/types"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/rpc"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
)
const (
// Blockchain ..
Blockchain = "Harmony"
// Symbol ..
Symbol = "ONE"
// Decimals ..
Decimals = 18
// CurveType ..
CurveType = types.Secp256k1
)
var (
// TransactionTypes ..
TransactionTypes = []string{
"Transfer",
"CrossShardTransfer",
staking.DirectiveCreateValidator.String(),
staking.DirectiveEditValidator.String(),
staking.DirectiveDelegate.String(),
staking.DirectiveUndelegate.String(),
staking.DirectiveCollectRewards.String(),
}
// ReadTimeout ..
ReadTimeout = 30 * time.Second
// WriteTimeout ..
WriteTimeout = 30 * time.Second
// IdleTimeout ..
IdleTimeout = 120 * time.Second
)
// ShardMetadata for the network identifier
type ShardMetadata struct {
IsBeacon bool `json:"isBeacon"`
}
// GetNetwork fetches the networking identifier for the given shard
func GetNetwork(shardID uint32) *types.NetworkIdentifier {
metadata, _ := rpc.NewStructuredResponse(ShardMetadata{
IsBeacon: shardID == shard.BeaconChainShardID,
})
return &types.NetworkIdentifier{
Blockchain: Blockchain,
Network: getNetworkName(),
SubNetworkIdentifier: &types.SubNetworkIdentifier{
Network: fmt.Sprintf("shard %d", shardID),
Metadata: metadata,
},
}
}
func getNetworkName() string {
if shard.Schedule.GetNetworkID() == shardingconfig.MainNet {
return "Mainnet"
}
return "Testnet"
}

@ -0,0 +1,87 @@
package rosetta
import (
"fmt"
"net"
"net/http"
"time"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/harmony-one/harmony/hmy"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
common "github.com/harmony-one/harmony/rosetta/common"
"github.com/harmony-one/harmony/rosetta/services"
)
// StartServers starts the rosetta http server
func StartServers(hmy *hmy.Harmony, config nodeconfig.RosettaServerConfig) error {
if !config.HTTPEnabled {
utils.Logger().Info().Msg("Rosetta http server disabled...")
return nil
}
network := common.GetNetwork(hmy.ShardID)
serverAsserter, err := asserter.NewServer(
common.TransactionTypes,
nodeconfig.GetDefaultConfig().Role() == nodeconfig.ExplorerNode,
[]*types.NetworkIdentifier{network},
)
if err != nil {
return err
}
router := server.CorsMiddleware(loggerMiddleware(getRouter(network, serverAsserter, hmy)))
utils.Logger().Info().
Int("port", config.HTTPPort).
Str("ip", config.HTTPIp).
Msg("Starting Rosetta server")
endpoint := fmt.Sprintf("%s:%d", config.HTTPIp, config.HTTPPort)
var (
listener net.Listener
)
if listener, err = net.Listen("tcp", endpoint); err != nil {
return err
}
go newHTTPServer(router).Serve(listener)
return nil
}
func newHTTPServer(handler http.Handler) *http.Server {
return &http.Server{
Handler: handler,
ReadTimeout: common.ReadTimeout,
WriteTimeout: common.WriteTimeout,
IdleTimeout: common.IdleTimeout,
}
}
func getRouter(
network *types.NetworkIdentifier,
asserter *asserter.Asserter,
hmy *hmy.Harmony,
) http.Handler {
return server.NewRouter(
server.NewNetworkAPIController(services.NewNetworkAPIService(network, hmy), asserter),
server.NewBlockAPIController(services.NewBlockAPIService(network, hmy), asserter),
)
}
func loggerMiddleware(router http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
router.ServeHTTP(w, r)
msg := fmt.Sprintf(
"Rosetta: %s %s %s",
r.Method,
r.RequestURI,
time.Since(start),
)
utils.Logger().Info().Msg(msg)
// Print to stdout for quick check of rosetta activity
fmt.Printf("%s %s\n", time.Now().Format("2006-01-02 15:04:05"), msg)
})
}

@ -0,0 +1,158 @@
package services
import (
"context"
"fmt"
"time"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/harmony-one/harmony/hmy"
)
// BlockAPIService implements the server.BlockAPIServicer interface.
type BlockAPIService struct {
hmy *hmy.Harmony
network *types.NetworkIdentifier
}
// NewBlockAPIService creates a new instance of a BlockAPIService.
func NewBlockAPIService(
network *types.NetworkIdentifier, hmy *hmy.Harmony,
) server.BlockAPIServicer {
return &BlockAPIService{
hmy: hmy,
network: network,
}
}
// Block implements the /block endpoint (placeholder)
// FIXME: remove placeholder & implement block endpoint
func (s *BlockAPIService) Block(
ctx context.Context,
request *types.BlockRequest,
) (*types.BlockResponse, *types.Error) {
if *request.BlockIdentifier.Index != 1000 {
previousBlockIndex := *request.BlockIdentifier.Index - 1
if previousBlockIndex < 0 {
previousBlockIndex = 0
}
return &types.BlockResponse{
Block: &types.Block{
BlockIdentifier: &types.BlockIdentifier{
Index: *request.BlockIdentifier.Index,
Hash: fmt.Sprintf("block %d", *request.BlockIdentifier.Index),
},
ParentBlockIdentifier: &types.BlockIdentifier{
Index: previousBlockIndex,
Hash: fmt.Sprintf("block %d", previousBlockIndex),
},
Timestamp: time.Now().UnixNano() / 1000000,
Transactions: []*types.Transaction{},
},
}, nil
}
return &types.BlockResponse{
Block: &types.Block{
BlockIdentifier: &types.BlockIdentifier{
Index: 1000,
Hash: "block 1000",
},
ParentBlockIdentifier: &types.BlockIdentifier{
Index: 999,
Hash: "block 999",
},
Timestamp: 1586483189000,
Transactions: []*types.Transaction{
{
TransactionIdentifier: &types.TransactionIdentifier{
Hash: "transaction 0",
},
Operations: []*types.Operation{
{
OperationIdentifier: &types.OperationIdentifier{
Index: 0,
},
Type: "Transfer",
Status: "Success",
Account: &types.AccountIdentifier{
Address: "account 0",
},
Amount: &types.Amount{
Value: "-1000",
Currency: &types.Currency{
Symbol: "ROS",
Decimals: 2,
},
},
},
{
OperationIdentifier: &types.OperationIdentifier{
Index: 1,
},
RelatedOperations: []*types.OperationIdentifier{
{
Index: 0,
},
},
Type: "Transfer",
Status: "Reverted",
Account: &types.AccountIdentifier{
Address: "account 1",
},
Amount: &types.Amount{
Value: "1000",
Currency: &types.Currency{
Symbol: "ROS",
Decimals: 2,
},
},
},
},
},
},
},
OtherTransactions: []*types.TransactionIdentifier{
{
Hash: "transaction 1",
},
},
}, nil
}
// BlockTransaction implements the /block/transaction endpoint (placeholder)
// FIXME: remove placeholder & implement block endpoint
func (s *BlockAPIService) BlockTransaction(
ctx context.Context,
request *types.BlockTransactionRequest,
) (*types.BlockTransactionResponse, *types.Error) {
return &types.BlockTransactionResponse{
Transaction: &types.Transaction{
TransactionIdentifier: &types.TransactionIdentifier{
Hash: "transaction 1",
},
Operations: []*types.Operation{
{
OperationIdentifier: &types.OperationIdentifier{
Index: 0,
},
Type: "Reward",
Status: "Success",
Account: &types.AccountIdentifier{
Address: "account 2",
},
Amount: &types.Amount{
Value: "1000",
Currency: &types.Currency{
Symbol: "ROS",
Decimals: 2,
},
},
},
},
},
}, nil
}

@ -0,0 +1,100 @@
package services
import (
"context"
"github.com/coinbase/rosetta-sdk-go/server"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/harmony-one/harmony/hmy"
)
// NetworkAPIService implements the server.NetworkAPIServicer interface.
type NetworkAPIService struct {
hmy *hmy.Harmony
network *types.NetworkIdentifier
}
// NewNetworkAPIService creates a new instance of a NetworkAPIService.
func NewNetworkAPIService(
network *types.NetworkIdentifier, hmy *hmy.Harmony,
) server.NetworkAPIServicer {
return &NetworkAPIService{
hmy: hmy,
network: network,
}
}
// NetworkList implements the /network/list endpoint (placeholder)
// FIXME: remove placeholder & implement block endpoint
func (s *NetworkAPIService) NetworkList(
ctx context.Context,
request *types.MetadataRequest,
) (*types.NetworkListResponse, *types.Error) {
return &types.NetworkListResponse{
NetworkIdentifiers: []*types.NetworkIdentifier{
s.network,
},
}, nil
}
// NetworkStatus implements the /network/status endpoint (placeholder)
// FIXME: remove placeholder & implement block endpoint
func (s *NetworkAPIService) NetworkStatus(
ctx context.Context,
request *types.NetworkRequest,
) (*types.NetworkStatusResponse, *types.Error) {
return &types.NetworkStatusResponse{
CurrentBlockIdentifier: &types.BlockIdentifier{
Index: 1000,
Hash: "block 1000",
},
CurrentBlockTimestamp: int64(1586483189000),
GenesisBlockIdentifier: &types.BlockIdentifier{
Index: 0,
Hash: "block 0",
},
Peers: []*types.Peer{
{
PeerID: "peer 1",
},
},
}, nil
}
// NetworkOptions implements the /network/options endpoint (placeholder)
// FIXME: remove placeholder & implement block endpoint
func (s *NetworkAPIService) NetworkOptions(
ctx context.Context,
request *types.NetworkRequest,
) (*types.NetworkOptionsResponse, *types.Error) {
return &types.NetworkOptionsResponse{
Version: &types.Version{
RosettaVersion: "1.4.0",
NodeVersion: "0.0.1",
},
Allow: &types.Allow{
OperationStatuses: []*types.OperationStatus{
{
Status: "Success",
Successful: true,
},
{
Status: "Reverted",
Successful: false,
},
},
OperationTypes: []string{
"Transfer",
"Reward",
},
Errors: []*types.Error{
{
Code: 1,
Message: "not implemented",
Retriable: false,
},
},
},
}, nil
}

@ -82,7 +82,7 @@ function launch_localnet() {
# Read config for i-th node form config file
IFS=' ' read -r ip port mode bls_key shard <<<"${line}"
args=("${base_args[@]}" --ip "${ip}" --port "${port}" --key "/tmp/${ip}-${port}.key" --db_dir "${ROOT}/db-${ip}-${port}" "--broadcast_invalid_tx=true")
args=("${base_args[@]}" --ip "${ip}" --port "${port}" --key "/tmp/${ip}-${port}.key" --db_dir "${ROOT}/db-${ip}-${port}" "--broadcast_invalid_tx=false")
if [[ -z "$ip" || -z "$port" ]]; then
echo "skip empty node"
continue
@ -103,7 +103,7 @@ function launch_localnet() {
# Setup flags for i-th node based on config
case "${mode}" in
explorer)
args=("${args[@]}" "--node_type=explorer" "--shard_id=${shard}")
args=("${args[@]}" "--node_type=explorer" "--shard_id=${shard}" "--http.rosetta=true")
;;
archival)
args=("${args[@]}" --is_archival --run.legacy)

Loading…
Cancel
Save