From f57bb64c56a15dd40dc4f7e0f624c231f09752d6 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 21 Mar 2023 03:02:48 -0300 Subject: [PATCH 001/134] [state] fix: use prefix on state trie keys --- pkg/trie/trie.go | 13 ++++++++++++- pkg/trie/trie_cache.go | 3 +-- pkg/trie/trie_revert.go | 4 ++-- pkg/trie/trie_test.go | 10 +++++----- pkg/trie/trie_tools.go | 4 ++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/pkg/trie/trie.go b/pkg/trie/trie.go index 37f018f5f..7ac295a47 100644 --- a/pkg/trie/trie.go +++ b/pkg/trie/trie.go @@ -13,6 +13,13 @@ import ( "github.com/aergoio/aergo-lib/db" ) + +var ( + // triePrefix is the prefix for the trie keys in the db. + triePrefix = []byte{'s'} +) + + // Trie is a modified sparse Merkle tree. // Instead of storing values at the leaves of the tree, // the values are stored at the highest subtree root that contains only that value. @@ -482,7 +489,7 @@ func (s *Trie) loadBatch(root []byte) ([][]byte, error) { s.loadDbMux.Unlock() } s.db.lock.Lock() - dbval := s.db.Store.Get(root[:HashLength]) + dbval := s.db.Store.Get(trieKey(root[:HashLength])) s.db.lock.Unlock() nodeSize := len(dbval) if nodeSize != 0 { @@ -583,3 +590,7 @@ func (s *Trie) updatePastTries() { s.pastTries = append(s.pastTries, s.Root) } } + +func trieKey(key []byte) []byte { + return append(triePrefix, key...) +} diff --git a/pkg/trie/trie_cache.go b/pkg/trie/trie_cache.go index 3c41da5ad..d765006e9 100644 --- a/pkg/trie/trie_cache.go +++ b/pkg/trie/trie_cache.go @@ -41,8 +41,7 @@ func (c *CacheDB) commit(txn *DbTx) { c.updatedMux.Lock() defer c.updatedMux.Unlock() for key, batch := range c.updatedNodes { - var node []byte - (*txn).Set(append(node, key[:]...), c.serializeBatch(batch)) + (*txn).Set(trieKey(key[:]), c.serializeBatch(batch)) } } diff --git a/pkg/trie/trie_revert.go b/pkg/trie/trie_revert.go index 5dd6e5b05..fdc4fe124 100644 --- a/pkg/trie/trie_revert.go +++ b/pkg/trie/trie_revert.go @@ -50,7 +50,7 @@ func (s *Trie) Revert(toOldRoot []byte) error { // NOTE The tx interface doesnt handle ErrTxnTooBig txn := s.db.Store.NewTx() for _, key := range s.db.nodesToRevert { - txn.Delete(key[:HashLength]) + txn.Delete(trieKey(key[:HashLength])) } txn.Commit() @@ -62,7 +62,7 @@ func (s *Trie) Revert(toOldRoot []byte) error { // If toOldRoot is a shortcut batch, it is possible that // revert has deleted it if the key was ever stored at height0 // because in leafHash byte(0) = byte(256) - s.db.Store.Set(toOldRoot, s.db.serializeBatch(batch)) + s.db.Store.Set(trieKey(toOldRoot), s.db.serializeBatch(batch)) } return nil } diff --git a/pkg/trie/trie_test.go b/pkg/trie/trie_test.go index ab45e97fa..a8c5cd9ff 100644 --- a/pkg/trie/trie_test.go +++ b/pkg/trie/trie_test.go @@ -364,10 +364,10 @@ func TestTrieRevert(t *testing.T) { root2, _ := smt.Update([][]byte{key1}, [][]byte{values[1]}) smt.Commit() smt.Revert(root) - if len(smt.db.Store.Get(root)) == 0 { + if len(smt.db.Store.Get(trieKey(root))) == 0 { t.Fatal("shortcut node shouldnt be deleted by revert") } - if len(smt.db.Store.Get(root2)) != 0 { + if len(smt.db.Store.Get(trieKey(root2))) != 0 { t.Fatal("reverted root should have been deleted") } key1 = make([]byte, 32, 32) @@ -376,7 +376,7 @@ func TestTrieRevert(t *testing.T) { smt.Update([][]byte{key1}, [][]byte{values[1]}) smt.Commit() smt.Revert(root) - if len(smt.db.Store.Get(root)) == 0 { + if len(smt.db.Store.Get(trieKey(root))) == 0 { t.Fatal("shortcut node shouldnt be deleted by revert") } @@ -418,12 +418,12 @@ func TestTrieRevert(t *testing.T) { } // Check all reverted nodes have been deleted for node, _ := range updatedNodes2 { - if len(smt.db.Store.Get(node[:])) != 0 { + if len(smt.db.Store.Get(trieKey(node[:]))) != 0 { t.Fatal("nodes not deleted from database", node) } } for node, _ := range updatedNodes1 { - if len(smt.db.Store.Get(node[:])) != 0 { + if len(smt.db.Store.Get(trieKey(node[:]))) != 0 { t.Fatal("nodes not deleted from database", node) } } diff --git a/pkg/trie/trie_tools.go b/pkg/trie/trie_tools.go index ffab213e4..63105148c 100644 --- a/pkg/trie/trie_tools.go +++ b/pkg/trie/trie_tools.go @@ -35,7 +35,7 @@ func (s *Trie) loadCache(root []byte, batch [][]byte, iBatch, height int, ch cha if height%4 == 0 { // Load the node from db s.db.lock.Lock() - dbval := s.db.Store.Get(root[:HashLength]) + dbval := s.db.Store.Get(trieKey(root[:HashLength])) s.db.lock.Unlock() if len(dbval) == 0 { ch <- fmt.Errorf("the trie node %x is unavailable in the disk db, db may be corrupted", root) @@ -113,7 +113,7 @@ func (s *Trie) get(root, key []byte, batch [][]byte, iBatch, height int) ([]byte // TrieRootExists returns true if the root exists in Database. func (s *Trie) TrieRootExists(root []byte) bool { s.db.lock.RLock() - dbval := s.db.Store.Get(root) + dbval := s.db.Store.Get(trieKey(root)) s.db.lock.RUnlock() if len(dbval) != 0 { return true From aa1d7d30fd1c007c3e4ed8c92c2c00224473d60a Mon Sep 17 00:00:00 2001 From: jinuk Date: Wed, 16 Aug 2023 16:54:11 +0900 Subject: [PATCH 002/134] - Define web3 API - Add swagger-ui --- cmd/aergosvr/aergosvr.go | 4 +- go.mod | 1 + go.sum | 2 + rpc/grpcserver.go | 4 + rpc/rpc.go | 735 ++++++++++++++++++------------------- rpc/web3/v1.go | 495 +++++++++++++++++++++++++ rpc/web3/web3.go | 80 ++++ swagger/swagger-ui.html | 26 ++ swagger/swagger.yaml | 761 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 1746 insertions(+), 362 deletions(-) create mode 100644 rpc/web3/v1.go create mode 100644 rpc/web3/web3.go create mode 100644 swagger/swagger-ui.html create mode 100644 swagger/swagger.yaml diff --git a/cmd/aergosvr/aergosvr.go b/cmd/aergosvr/aergosvr.go index 220d637ef..9cfb7e70f 100644 --- a/cmd/aergosvr/aergosvr.go +++ b/cmd/aergosvr/aergosvr.go @@ -23,6 +23,7 @@ import ( "github.com/aergoio/aergo/pkg/component" polarisclient "github.com/aergoio/aergo/polaris/client" "github.com/aergoio/aergo/rpc" + "github.com/aergoio/aergo/rpc/web3" "github.com/aergoio/aergo/syncer" "github.com/spf13/cobra" ) @@ -123,7 +124,8 @@ func rootRun(cmd *cobra.Command, args []string) { syncSvc := syncer.NewSyncer(cfg, chainSvc, nil) p2pSvc := p2p.NewP2P(cfg, chainSvc) pmapSvc := polarisclient.NewPolarisConnectSvc(cfg.P2P, p2pSvc) - + web3.NewWeb3(rpcSvc.GetActualServer()) + var accountSvc component.IComponent if cfg.Personal { accountSvc = account.NewAccountService(cfg, chainSvc.SDB()) diff --git a/go.mod b/go.mod index 1d4b10b33..402e3d2af 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( require ( github.com/Workiva/go-datastructures v1.0.50 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect diff --git a/go.sum b/go.sum index ba5c1cd4a..c36ed46e4 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/anaskhan96/base58check v0.0.0-20181220122047-b05365d494c4 h1:FUDNaUiPOxrVtUmsRSdx7hrvCKXpfQafPpPU0Yh27os= github.com/anaskhan96/base58check v0.0.0-20181220122047-b05365d494c4/go.mod h1:glPG1rmt/bD3wEXWanFIuoPjC4MG+JEN+i7YhwEYA/Y= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= diff --git a/rpc/grpcserver.go b/rpc/grpcserver.go index 02b933f3b..3207df40f 100644 --- a/rpc/grpcserver.go +++ b/rpc/grpcserver.go @@ -74,6 +74,10 @@ const defaultActorTimeout = time.Second * 3 var _ types.AergoRPCServiceServer = (*AergoRPCService)(nil) +func (ns *AergoRPCService) GetActorHelper() p2pcommon.ActorService { + return ns.actorHelper +} + func (rpc *AergoRPCService) SetConsensusAccessor(ca consensus.ConsensusAccessor) { if rpc == nil { return diff --git a/rpc/rpc.go b/rpc/rpc.go index b41bef127..49640eb91 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -39,369 +39,382 @@ import ( ) // RPC is actor for providing rpc service -type RPC struct { - conf *config.Config - - *component.BaseComponent - - grpcServer *grpc.Server - grpcWebServer *grpcweb.WrappedGrpcServer - actualServer *AergoRPCService - httpServer *http.Server - - ca types.ChainAccessor - version string - entConf *types.EnterpriseConfig -} - -//var _ component.IComponent = (*RPCComponent)(nil) - -// NewRPC create an rpc service -func NewRPC(cfg *config.Config, chainAccessor types.ChainAccessor, version string) *RPC { - actualServer := &AergoRPCService{ - msgHelper: message.GetHelper(), - blockStream: make(map[uint32]*ListBlockStream), - blockMetadataStream: make(map[uint32]*ListBlockMetaStream), - eventStream: make(map[*EventStream]*EventStream), - } - - tracer := opentracing.GlobalTracer() - - opts := make([]grpc.ServerOption, 0) - - if cfg.RPC.NetServiceTrace { - opts = append(opts, grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer))) - opts = append(opts, grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer))) - } - - var entConf *types.EnterpriseConfig - genesis := chainAccessor.GetGenesisInfo() - if !genesis.ID.PublicNet { - conf, err := chainAccessor.GetEnterpriseConfig("rpcpermissions") - if err != nil { - logger.Error().Err(err).Msg("could not get allowed client information") - } else { - entConf = conf - } - } - - if cfg.RPC.NSEnableTLS { - certificate, err := tls.LoadX509KeyPair(cfg.RPC.NSCert, cfg.RPC.NSKey) - if err != nil { - logger.Error().Err(err).Msg("could not load server key pair") - } - certPool := x509.NewCertPool() - ca, err := ioutil.ReadFile(cfg.RPC.NSCACert) - if err != nil { - logger.Error().Err(err).Msg("could not read CA cert") - } - if ok := certPool.AppendCertsFromPEM(ca); !ok { - logger.Error().Bool("AppendCertsFromPEM", ok).Msg("failed to append server cert") - err = fmt.Errorf("failed to append server cert") - } - if err == nil { - creds := credentials.NewTLS(&tls.Config{ - ClientAuth: tls.RequireAndVerifyClientCert, - Certificates: []tls.Certificate{certificate}, - ClientCAs: certPool, - }) - opts = append(opts, grpc.Creds(creds)) - logger.Info().Str("cert", cfg.RPC.NSCert).Str("key", cfg.RPC.NSKey).Msg("grpc with TLS") - } - } - - grpcServer := network.GRPCSeverBuilder(). - MessageSize(int(types.GetMaxMessageSize(cfg.Blockchain.MaxBlockSize))). - Opts(opts). - GetInstance() - - grpcWebServer := grpcweb.WrapServer( - grpcServer, - grpcweb.WithWebsockets(true), - grpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool { - return true - })) - - rpcsvc := &RPC{ - conf: cfg, - - grpcServer: grpcServer, - grpcWebServer: grpcWebServer, - actualServer: actualServer, - ca: chainAccessor, - version: version, - } - rpcsvc.BaseComponent = component.NewBaseComponent(message.RPCSvc, rpcsvc, logger) - - actualServer.actorHelper = rpcsvc - actualServer.setClientAuth(entConf) - - rpcsvc.httpServer = &http.Server{ - Handler: rpcsvc.grpcWebHandlerFunc(grpcWebServer, http.DefaultServeMux), - ReadTimeout: 4 * time.Second, - WriteTimeout: 4 * time.Second, - MaxHeaderBytes: 1 << 20, - } - - return rpcsvc -} - -func (ns *RPC) SetHub(hub *component.ComponentHub) { - ns.actualServer.hub = hub - ns.BaseComponent.SetHub(hub) -} - -func (ns *RPC) SetConsensusAccessor(ca consensus.ConsensusAccessor) { - ns.actualServer.SetConsensusAccessor(ca) -} - -// Start start rpc service. -func (ns *RPC) BeforeStart() { - aergorpc.RegisterAergoRPCServiceServer(ns.grpcServer, ns.actualServer) -} - -func (ns *RPC) AfterStart() { - go ns.serve() -} - -// Stop stops rpc service. -func (ns *RPC) BeforeStop() { - ns.httpServer.Close() - ns.grpcServer.Stop() -} - -func (ns *RPC) Statistics() *map[string]interface{} { - return &map[string]interface{}{ - "config": ns.conf.RPC, - "version": ns.version, - "streams": ns.actualServer.Statistics(), - } -} - -func (ns *RPC) Receive(context actor.Context) { - switch msg := context.Message().(type) { - case *types.Block: - server := ns.actualServer - server.BroadcastToListBlockStream(msg) - meta := msg.GetMetadata() - server.BroadcastToListBlockMetadataStream(meta) - case []*types.Event: - server := ns.actualServer - for _, e := range msg { - if bytes.Equal(e.GetContractAddress(), types.AddressPadding([]byte(types.AergoEnterprise))) { - eventName := strings.Split(e.GetEventName(), " ") - conf := strings.ToUpper(eventName[1]) - switch eventName[0] { - case "Enable": - if conf == enterprise.RPCPermissions { - value := false - if e.JsonArgs == "true" { - value = true - } - server.setClientAuthOn(value) - } else if conf == enterprise.AccountWhite { - value := false - if e.JsonArgs == "true" { - value = true - } - msg := &message.MemPoolEnableWhitelist{On: value} - ns.TellTo(message.MemPoolSvc, msg) - } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { - value := false - if e.JsonArgs == "true" { - value = true - } - msg := message.P2PWhiteListConfEnableEvent{Name: conf, On: value} - ns.TellTo(message.P2PSvc, msg) - } - case "Set": - if conf == enterprise.RPCPermissions { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - server.setClientAuthMap(values) - } else if conf == enterprise.AccountWhite { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - msg := &message.MemPoolSetWhitelist{ - Accounts: values, - } - ns.TellTo(message.MemPoolSvc, msg) - } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - msg := message.P2PWhiteListConfSetEvent{ - Values: values, - } - ns.TellTo(message.P2PSvc, msg) - } - default: - logger.Warn().Str("Enterprise event", eventName[0]).Str("conf", conf).Msg("unknown message in RPCPERMISSION") - } - } - } - server.BroadcastToEventStream(msg) - case *message.GetServerInfo: - context.Respond(ns.CollectServerInfo(msg.Categories)) - case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing - // Ignore actor lfiecycle messages - default: - ns.Warn().Msgf("unknown msg received in rpc %s", reflect.TypeOf(msg).String()) - } -} - -// Create HTTP handler that redirects matching grpc-web requests to the grpc-web wrapper. -func (ns *RPC) grpcWebHandlerFunc(grpcWebServer *grpcweb.WrappedGrpcServer, otherHandler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + type RPC struct { + conf *config.Config + + *component.BaseComponent + + grpcServer *grpc.Server + grpcWebServer *grpcweb.WrappedGrpcServer + actualServer *AergoRPCService + httpServer *http.Server + + ca types.ChainAccessor + version string + entConf *types.EnterpriseConfig + } + + //var _ component.IComponent = (*RPCComponent)(nil) + + // NewRPC create an rpc service + func NewRPC(cfg *config.Config, chainAccessor types.ChainAccessor, version string) *RPC { + actualServer := &AergoRPCService{ + msgHelper: message.GetHelper(), + blockStream: make(map[uint32]*ListBlockStream), + blockMetadataStream: make(map[uint32]*ListBlockMetaStream), + eventStream: make(map[*EventStream]*EventStream), + } + + tracer := opentracing.GlobalTracer() + + opts := make([]grpc.ServerOption, 0) + + if cfg.RPC.NetServiceTrace { + opts = append(opts, grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer))) + opts = append(opts, grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer))) + } + + var entConf *types.EnterpriseConfig + genesis := chainAccessor.GetGenesisInfo() + if !genesis.ID.PublicNet { + conf, err := chainAccessor.GetEnterpriseConfig("rpcpermissions") + if err != nil { + logger.Error().Err(err).Msg("could not get allowed client information") + } else { + entConf = conf + } + } + + if cfg.RPC.NSEnableTLS { + certificate, err := tls.LoadX509KeyPair(cfg.RPC.NSCert, cfg.RPC.NSKey) + if err != nil { + logger.Error().Err(err).Msg("could not load server key pair") + } + certPool := x509.NewCertPool() + ca, err := ioutil.ReadFile(cfg.RPC.NSCACert) + if err != nil { + logger.Error().Err(err).Msg("could not read CA cert") + } + if ok := certPool.AppendCertsFromPEM(ca); !ok { + logger.Error().Bool("AppendCertsFromPEM", ok).Msg("failed to append server cert") + err = fmt.Errorf("failed to append server cert") + } + if err == nil { + creds := credentials.NewTLS(&tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + Certificates: []tls.Certificate{certificate}, + ClientCAs: certPool, + }) + opts = append(opts, grpc.Creds(creds)) + logger.Info().Str("cert", cfg.RPC.NSCert).Str("key", cfg.RPC.NSKey).Msg("grpc with TLS") + } + } + + grpcServer := network.GRPCSeverBuilder(). + MessageSize(int(types.GetMaxMessageSize(cfg.Blockchain.MaxBlockSize))). + Opts(opts). + GetInstance() + + grpcWebServer := grpcweb.WrapServer( + grpcServer, + grpcweb.WithWebsockets(true), + grpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool { + return true + })) + + rpcsvc := &RPC{ + conf: cfg, + + grpcServer: grpcServer, + grpcWebServer: grpcWebServer, + actualServer: actualServer, + ca: chainAccessor, + version: version, + } + rpcsvc.BaseComponent = component.NewBaseComponent(message.RPCSvc, rpcsvc, logger) + + actualServer.actorHelper = rpcsvc + actualServer.setClientAuth(entConf) + + rpcsvc.httpServer = &http.Server{ + Handler: rpcsvc.grpcWebHandlerFunc(grpcWebServer, http.DefaultServeMux, actualServer), + ReadTimeout: 4 * time.Second, + WriteTimeout: 4 * time.Second, + MaxHeaderBytes: 1 << 20, + } + + return rpcsvc + } + + func (ns *RPC) GetActualServer() *AergoRPCService { + return ns.actualServer + } + + func (ns *RPC) SetHub(hub *component.ComponentHub) { + ns.actualServer.hub = hub + ns.BaseComponent.SetHub(hub) + } + + func (ns *RPC) SetConsensusAccessor(ca consensus.ConsensusAccessor) { + ns.actualServer.SetConsensusAccessor(ca) + } + + // Start start rpc service. + func (ns *RPC) BeforeStart() { + aergorpc.RegisterAergoRPCServiceServer(ns.grpcServer, ns.actualServer) + } + + func (ns *RPC) AfterStart() { + go ns.serve() + } + + // Stop stops rpc service. + func (ns *RPC) BeforeStop() { + ns.httpServer.Close() + ns.grpcServer.Stop() + } + + func (ns *RPC) Statistics() *map[string]interface{} { + return &map[string]interface{}{ + "config": ns.conf.RPC, + "version": ns.version, + "streams": ns.actualServer.Statistics(), + } + } + + func (ns *RPC) Receive(context actor.Context) { + switch msg := context.Message().(type) { + case *types.Block: + server := ns.actualServer + server.BroadcastToListBlockStream(msg) + meta := msg.GetMetadata() + server.BroadcastToListBlockMetadataStream(meta) + case []*types.Event: + server := ns.actualServer + for _, e := range msg { + if bytes.Equal(e.GetContractAddress(), types.AddressPadding([]byte(types.AergoEnterprise))) { + eventName := strings.Split(e.GetEventName(), " ") + conf := strings.ToUpper(eventName[1]) + switch eventName[0] { + case "Enable": + if conf == enterprise.RPCPermissions { + value := false + if e.JsonArgs == "true" { + value = true + } + server.setClientAuthOn(value) + } else if conf == enterprise.AccountWhite { + value := false + if e.JsonArgs == "true" { + value = true + } + msg := &message.MemPoolEnableWhitelist{On: value} + ns.TellTo(message.MemPoolSvc, msg) + } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { + value := false + if e.JsonArgs == "true" { + value = true + } + msg := message.P2PWhiteListConfEnableEvent{Name: conf, On: value} + ns.TellTo(message.P2PSvc, msg) + } + case "Set": + if conf == enterprise.RPCPermissions { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + server.setClientAuthMap(values) + } else if conf == enterprise.AccountWhite { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + msg := &message.MemPoolSetWhitelist{ + Accounts: values, + } + ns.TellTo(message.MemPoolSvc, msg) + } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + msg := message.P2PWhiteListConfSetEvent{ + Values: values, + } + ns.TellTo(message.P2PSvc, msg) + } + default: + logger.Warn().Str("Enterprise event", eventName[0]).Str("conf",conf).Msg("unknown message in RPCPERMISSION") + } + } + } + server.BroadcastToEventStream(msg) + case *message.GetServerInfo: + context.Respond(ns.CollectServerInfo(msg.Categories)) + case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing + // Ignore actor lfiecycle messages + default: + ns.Warn().Msgf("unknown msg received in rpc %s", reflect.TypeOf(msg).String()) + } + } + + // Create HTTP handler that redirects matching grpc-web requests to the grpc-web wrapper. + func (ns *RPC) grpcWebHandlerFunc(grpcWebServer *grpcweb.WrappedGrpcServer, otherHandler http.Handler, actualServer *AergoRPCService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if grpcWebServer.IsAcceptableGrpcCorsRequest(r) || grpcWebServer.IsGrpcWebRequest(r) || grpcWebServer.IsGrpcWebSocketRequest(r) { - grpcWebServer.ServeHTTP(w, r) + grpcWebServer.ServeHTTP(w, r) } else { ns.Info().Msg("Request handled by other hanlder. is this correct?") otherHandler.ServeHTTP(w, r) + // handler, ok := restAPIHandler(actualServer, r) + + // if(ok) { + // handler.ServeHTTP(w, r) + // }else{ + // ns.Info().Msg("Request handled by other hanlder. is this correct?") + // otherHandler.ServeHTTP(w, r) + // } } - }) -} - -// Serve GRPC server over TCP -func (ns *RPC) serveGRPC(l net.Listener, server *grpc.Server) { - if err := server.Serve(l); err != nil { - switch err { - case cmux.ErrListenerClosed: - // Server killed, usually by ctrl-c signal - default: - panic(err) - } - } -} - -// Serve HTTP server over TCP -func (ns *RPC) serveHTTP(l net.Listener, server *http.Server) { - if err := server.Serve(l); err != nil && err != http.ErrServerClosed { - panic(err) - } -} - -// Serve TCP multiplexer -func (ns *RPC) serve() { - ipAddr := net.ParseIP(ns.conf.RPC.NetServiceAddr) - if ipAddr == nil { - panic("Wrong IP address format in RPC.NetServiceAddr") - } - - addr := fmt.Sprintf("%s:%d", ipAddr, ns.conf.RPC.NetServicePort) - - l, err := net.Listen("tcp", addr) - if err != nil { - panic(err) - } - - // Setup TCP multiplexer - tcpm := cmux.New(l) - - //grpcL := tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) - matchers := []cmux.Matcher{cmux.HTTP2()} - if ns.conf.RPC.NSEnableTLS { - matchers = append(matchers, cmux.TLS()) - } else { - //http1 only work without TLS - httpL := tcpm.Match(cmux.HTTP1Fast()) - go ns.serveHTTP(httpL, ns.httpServer) - } - grpcL := tcpm.Match(matchers...) - go ns.serveGRPC(grpcL, ns.grpcServer) - - ns.Info().Msg(fmt.Sprintf("Starting RPC server listening on %s, with TLS: %v", addr, ns.conf.RPC.NSEnableTLS)) - - // Serve TCP multiplexer - if err := tcpm.Serve(); !strings.Contains(err.Error(), "use of closed network connection") { - ns.Fatal().Msg(fmt.Sprintf("%v", err)) - } - - return -} - -func (ns *RPC) CollectServerInfo(categories []string) *types.ServerInfo { - // 3 items are needed - statusInfo := make(map[string]string) - rsp, err := ns.CallRequestDefaultTimeout(message.P2PSvc, &message.GetSelf{}) - statusInfo["version"] = ns.version - if err != nil { - ns.Logger.Error().Err(err).Msg("p2p actor error") - statusInfo["id"] = p2pkey.NodeSID() - } else { - meta := rsp.(p2pcommon.PeerMeta) - statusInfo["id"] = meta.ID.Pretty() - statusInfo["addr"] = meta.PrimaryAddress() - statusInfo["port"] = strconv.Itoa(int(meta.PrimaryPort())) - } - configInfo := make(map[string]*types.ConfigItem) - types.AddCategory(configInfo, "base").AddBool("personal", ns.conf.BaseConfig.Personal) - types.AddCategory(configInfo, "account").AddInt("unlocktimeout", int(ns.conf.Account.UnlockTimeout)) - return &types.ServerInfo{Status: statusInfo, Config: configInfo} -} - -const defaultTTL = time.Second * 4 - -// TellRequest implement interface method of ActorService -func (ns *RPC) TellRequest(actor string, msg interface{}) { - ns.TellTo(actor, msg) -} - -// SendRequest implement interface method of ActorService -func (ns *RPC) SendRequest(actor string, msg interface{}) { - ns.RequestTo(actor, msg) -} - -// FutureRequest implement interface method of ActorService -func (ns *RPC) FutureRequest(actor string, msg interface{}, timeout time.Duration) *actor.Future { - return ns.RequestToFuture(actor, msg, timeout) -} - -// FutureRequestDefaultTimeout implement interface method of ActorService -func (ns *RPC) FutureRequestDefaultTimeout(actor string, msg interface{}) *actor.Future { - return ns.RequestToFuture(actor, msg, defaultTTL) -} - -// CallRequest implement interface method of ActorService -func (ns *RPC) CallRequest(actor string, msg interface{}, timeout time.Duration) (interface{}, error) { - future := ns.RequestToFuture(actor, msg, timeout) - return future.Result() -} - -// CallRequest implement interface method of ActorService -func (ns *RPC) CallRequestDefaultTimeout(actor string, msg interface{}) (interface{}, error) { - future := ns.RequestToFuture(actor, msg, defaultTTL) - return future.Result() -} - -// GetChainAccessor implment interface method of ActorService -func (ns *RPC) GetChainAccessor() types.ChainAccessor { - return ns.ca -} - -func convertError(err error) types.CommitStatus { - switch err { - case nil: - return types.CommitStatus_TX_OK - case types.ErrTxNonceTooLow: - return types.CommitStatus_TX_NONCE_TOO_LOW - case types.ErrTxAlreadyInMempool: - return types.CommitStatus_TX_ALREADY_EXISTS - case types.ErrTxHasInvalidHash: - return types.CommitStatus_TX_INVALID_HASH - case types.ErrTxFormatInvalid: - return types.CommitStatus_TX_INVALID_FORMAT - case types.ErrInsufficientBalance: - return types.CommitStatus_TX_INSUFFICIENT_BALANCE - case types.ErrSameNonceAlreadyInMempool: - return types.CommitStatus_TX_HAS_SAME_NONCE - default: - //logger.Info().Str("hash", err.Error()).Msg("RPC encountered unconvertable error") - return types.CommitStatus_TX_INTERNAL_ERROR - } -} + }) + } + + // Serve GRPC server over TCP + func (ns *RPC) serveGRPC(l net.Listener, server *grpc.Server) { + if err := server.Serve(l); err != nil { + switch err { + case cmux.ErrListenerClosed: + // Server killed, usually by ctrl-c signal + default: + panic(err) + } + } + } + + // Serve HTTP server over TCP + func (ns *RPC) serveHTTP(l net.Listener, server *http.Server) { + if err := server.Serve(l); err != nil && err != http.ErrServerClosed { + panic(err) + } + } + + // Serve TCP multiplexer + func (ns *RPC) serve() { + ipAddr := net.ParseIP(ns.conf.RPC.NetServiceAddr) + if ipAddr == nil { + panic("Wrong IP address format in RPC.NetServiceAddr") + } + + addr := fmt.Sprintf("%s:%d", ipAddr, ns.conf.RPC.NetServicePort) + + l, err := net.Listen("tcp", addr) + if err != nil { + panic(err) + } + + // Setup TCP multiplexer + tcpm := cmux.New(l) + + //grpcL := tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) + matchers := []cmux.Matcher{cmux.HTTP2()} + if ns.conf.RPC.NSEnableTLS { + matchers = append(matchers, cmux.TLS()) + } else { + //http1 only work without TLS + httpL := tcpm.Match(cmux.HTTP1Fast()) + go ns.serveHTTP(httpL, ns.httpServer) + } + grpcL := tcpm.Match(matchers...) + go ns.serveGRPC(grpcL, ns.grpcServer) + + ns.Info().Msg(fmt.Sprintf("Starting RPC server listening on %s, with TLS: %v", addr, ns.conf.RPC.NSEnableTLS)) + + // Serve TCP multiplexer + if err := tcpm.Serve(); !strings.Contains(err.Error(), "use of closed network connection") { + ns.Fatal().Msg(fmt.Sprintf("%v", err)) + } + + return + } + + func (ns *RPC) CollectServerInfo(categories []string) *types.ServerInfo { + // 3 items are needed + statusInfo := make(map[string]string) + rsp, err := ns.CallRequestDefaultTimeout(message.P2PSvc, &message.GetSelf{}) + statusInfo["version"] = ns.version + if err != nil { + ns.Logger.Error().Err(err).Msg("p2p actor error") + statusInfo["id"] = p2pkey.NodeSID() + } else { + meta := rsp.(p2pcommon.PeerMeta) + statusInfo["id"] = meta.ID.Pretty() + statusInfo["addr"] = meta.PrimaryAddress() + statusInfo["port"] = strconv.Itoa(int(meta.PrimaryPort())) + } + configInfo := make(map[string]*types.ConfigItem) + types.AddCategory(configInfo, "base").AddBool("personal", ns.conf.BaseConfig.Personal) + types.AddCategory(configInfo, "account").AddInt("unlocktimeout", int(ns.conf.Account.UnlockTimeout)) + return &types.ServerInfo{Status: statusInfo, Config: configInfo} + } + + const defaultTTL = time.Second * 4 + + // TellRequest implement interface method of ActorService + func (ns *RPC) TellRequest(actor string, msg interface{}) { + ns.TellTo(actor, msg) + } + + // SendRequest implement interface method of ActorService + func (ns *RPC) SendRequest(actor string, msg interface{}) { + ns.RequestTo(actor, msg) + } + + // FutureRequest implement interface method of ActorService + func (ns *RPC) FutureRequest(actor string, msg interface{}, timeout time.Duration) *actor.Future { + return ns.RequestToFuture(actor, msg, timeout) + } + + // FutureRequestDefaultTimeout implement interface method of ActorService + func (ns *RPC) FutureRequestDefaultTimeout(actor string, msg interface{}) *actor.Future { + return ns.RequestToFuture(actor, msg, defaultTTL) + } + + // CallRequest implement interface method of ActorService + func (ns *RPC) CallRequest(actor string, msg interface{}, timeout time.Duration) (interface{}, error) { + future := ns.RequestToFuture(actor, msg, timeout) + return future.Result() + } + + // CallRequest implement interface method of ActorService + func (ns *RPC) CallRequestDefaultTimeout(actor string, msg interface{}) (interface{}, error) { + future := ns.RequestToFuture(actor, msg, defaultTTL) + return future.Result() + } + + // GetChainAccessor implment interface method of ActorService + func (ns *RPC) GetChainAccessor() types.ChainAccessor { + return ns.ca + } + + func convertError(err error) types.CommitStatus { + switch err { + case nil: + return types.CommitStatus_TX_OK + case types.ErrTxNonceTooLow: + return types.CommitStatus_TX_NONCE_TOO_LOW + case types.ErrTxAlreadyInMempool: + return types.CommitStatus_TX_ALREADY_EXISTS + case types.ErrTxHasInvalidHash: + return types.CommitStatus_TX_INVALID_HASH + case types.ErrTxFormatInvalid: + return types.CommitStatus_TX_INVALID_FORMAT + case types.ErrInsufficientBalance: + return types.CommitStatus_TX_INSUFFICIENT_BALANCE + case types.ErrSameNonceAlreadyInMempool: + return types.CommitStatus_TX_HAS_SAME_NONCE + default: + //logger.Info().Str("hash", err.Error()).Msg("RPC encountered unconvertable error") + return types.CommitStatus_TX_INTERNAL_ERROR + } + } + \ No newline at end of file diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go new file mode 100644 index 000000000..aaa4b0871 --- /dev/null +++ b/rpc/web3/v1.go @@ -0,0 +1,495 @@ +package web3 + +import ( + "crypto/sha256" + "encoding/base64" + "encoding/binary" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/aergoio/aergo/rpc" + "github.com/aergoio/aergo/types" + "github.com/asaskevich/govalidator" + "github.com/mr-tron/base58" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type Web3APIv1 struct { + rpc *rpc.AergoRPCService + request *http.Request +} + +func (api *Web3APIv1) handler(w http.ResponseWriter, r *http.Request) { + api.request = r; + + handler, ok := api.restAPIHandler(r) + if(ok) { + handler.ServeHTTP(w, r) + + } else { + http.NotFound(w, r) + } +} + +func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok bool) { + path := r.URL.Path + path = strings.TrimPrefix(path, prefixV1) + + if r.Method == http.MethodGet { + switch path { + case "/getAccounts": return api.GetAccounts(); + case "/getState": return api.GetState(); + case "/getProof": return api.GetStateAndProof(); + case "/getNameInfo": return api.GetNameInfo(); + case "/getBlock": return api.GetBlock(); + case "/getBlockNumber": return api.Blockchain(); + case "/getBlockBody": return api.GetBlockBody(); + case "/listBlockHeaders": return api.ListBlockHeaders(); + case "/getBlockMetadata": return api.GetBlockMetadata(); + case "/getChainInfo": return api.GetChainInfo(); + case "/getConsencusInfo": return api.GetConsensusInfo(); + case "/getTransaction": return api.GetTX(); + case "/getTransactionReceipt": return api.GetReceipt(); + case "/getBlockTX": return api.GetBlockTX(); + case "/verifyTX": return api.VerifyTX(); + case "/call": return api.QueryContract(); + case "/getPastEvents": return api.ListEvents(); + case "/getABI": return api.GetABI(); + case "/getAccountVotes": return api.GetAccountVotes(); + case "/queryContractState": return api.QueryContractState(); + case "/getNodeInfo": return api.NodeState(); + case "/getChainId": return api.GetPeers(); + case "/getServerInfo": return api.GetServerInfo(); + case "/getStaking": return api.GetStaking(); + case "/getVotes": return api.GetVotes(); + case "/metric": return api.Metric(); + case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); + case "/getConfChangeProgress": return api.GetConfChangeProgress(); + + // case "/getBalance": return api.GetBalance(); + // case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); + // case "/getTransactionCount": return api.GetTransactionCount(); + // case "/getBlockTransactionReceipts": return api.GetBlockTransactionReceipts(); + + case "/ChainStat": return api.ChainStat(); + case "/ListBlockMetadata": return api.ListBlockMetadata(); + + default: return nil, false + } + } else if r.Method == http.MethodPost { + switch path { + case "/sendSignedTransaction": return api.CommitTX(); + default: return nil, false + } + } + return nil, false +} + +func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.MetricsRequest{} + metricType := values.Get("type") + if metricType != "" { + request.Types = append(request.Types, types.MetricType(types.MetricType_value[metricType])) + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.Metric(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(api.rpc.GetAccounts(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + account := values.Get("account") + if account != "" { + request.Value = []byte(account) + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetState(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { + request := &types.AccountAndRoot{} + return commonResponseHandler(api.rpc.GetStateAndProof(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetNameInfo() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.Name{} + name := values.Get("name") + if name != "" { + request.Name = name + } + number := values.Get("number") + if number != "" { + numberValue, parseErr := strconv.ParseUint(number, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.BlockNo = numberValue + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetNameInfo(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base64.StdEncoding.DecodeString(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + + number := values.Get("number") + if number != "" { + numberValue, err := strconv.ParseUint(number, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + number := uint64(numberValue) // Replace with your actual value + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, number) + request.Value = byteValue + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetBlock(api.request.Context(), request)), true +} + +func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { + ca := api.rpc.GetActorHelper().GetChainAccessor() + last, err := ca.GetBestBlock() + if err != nil { + return nil, false + } + + digest := sha256.New() + digest.Write(last.GetHeader().GetChainID()) + bestChainIDHash := digest.Sum(nil) + + chainInfo, err := api.rpc.GetChainInfo(api.request.Context(), &types.Empty{}) + if err != nil { + logger.Warn().Err(err).Msg("failed to get chain info in blockchain") + chainInfo = nil + } + + return commonResponseHandler(&types.BlockchainStatus{ + BestBlockHash: last.BlockHash(), + BestHeight: last.GetHeader().GetBlockNo(), + ConsensusInfo: ca.GetConsensusInfo(), + BestChainIdHash: bestChainIDHash, + ChainInfo: chainInfo, + }, nil), true +} + +func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.BlockBodyParams{} + request.Paging = &types.PageParams{} + + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base64.StdEncoding.DecodeString(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Hashornumber = hashBytes + } + + number := values.Get("number") + if number != "" { + numberValue, err := strconv.ParseUint(number, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + number := uint64(numberValue) + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, number) + request.Hashornumber = byteValue + } + + size := values.Get("size") + if size != "" { + sizeValue, parseErr := strconv.ParseUint(size, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + + } + request.Paging.Size = uint32(sizeValue) + } + + offset := values.Get("offset") + if offset != "" { + offsetValue, parseErr := strconv.ParseUint(offset, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Paging.Offset = uint32(offsetValue) + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetBlockBody(api.request.Context(), request)), true +} + +func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.ListParams{} + height := values.Get("height") + if height != "" { + heightValue, parseErr := strconv.ParseUint(height, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Height = heightValue + } + + size := values.Get("size") + if size != "" { + sizeValue, parseErr := strconv.ParseUint(size, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Size = uint32(sizeValue) + } + + offset := values.Get("offset") + if offset != "" { + offsetValue, parseErr := strconv.ParseUint(offset, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Offset = uint32(offsetValue) + } + + asc := values.Get("asc") + if asc != "" { + ascValue, parseErr := strconv.ParseBool(asc) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Asc = ascValue + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.ListBlockHeaders(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base64.StdEncoding.DecodeString(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + + number := values.Get("number") + if number != "" { + numberValue, err := strconv.ParseUint(number, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + number := uint64(numberValue) // Replace with your actual value + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, number) + request.Value = byteValue + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetBlockMetadata(api.request.Context(), request)), true +} + +func (api *Web3APIv1) ListBlockMetadata() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} + + +func (api *Web3APIv1) GetChainInfo() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(api.rpc.GetChainInfo(api.request.Context(), request)), true +} + +func (api *Web3APIv1) ChainStat() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(api.rpc.ChainStat(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetConsensusInfo() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(api.rpc.GetConsensusInfo(api.request.Context(), request)), true +} + + +func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base58.Decode(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + return commonResponseHandler(api.rpc.GetReceipt(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) VerifyTX() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} +func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} + +func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true +} + diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go new file mode 100644 index 000000000..ec9120e91 --- /dev/null +++ b/rpc/web3/web3.go @@ -0,0 +1,80 @@ +package web3 + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/aergoio/aergo-lib/log" + "github.com/aergoio/aergo/rpc" +) + +type RestAPI struct { + rpc *rpc.AergoRPCService + request *http.Request +} + +var ( + prefixV1 = "/v1" +) + +var ( + logger = log.NewLogger("web3") +) + +func NewWeb3(rpc *rpc.AergoRPCService) { + // swagger setting + http.HandleFunc("/swagger.yaml", serveSwaggerYAML) + http.HandleFunc("/swagger", serveSwaggerUI) + + // v1 + web3svcV1 := &Web3APIv1{rpc: rpc} + http.HandleFunc("/v1/", web3svcV1.handler) + + go func() { + fmt.Println("Web3 Server is listening on port 80...") + http.ListenAndServe(":80", nil) + }() +} + +func serveSwaggerYAML(w http.ResponseWriter, r *http.Request) { + yamlContent, err := ioutil.ReadFile("./swagger/swagger.yaml") + if err != nil { + http.Error(w, "Failed to read YAML file", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/x-yaml") + w.Write(yamlContent) +} + +func serveSwaggerUI(w http.ResponseWriter, r *http.Request) { + htmlContent, err := ioutil.ReadFile("./swagger/swagger-ui.html") + if err != nil { + http.Error(w, "Failed to read HTML file", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "text/html") + w.Write(htmlContent) +} + +func commonResponseHandler(response interface{}, err error) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + jsonResponse, err := json.Marshal(response) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.Write(jsonResponse) + }) +} + diff --git a/swagger/swagger-ui.html b/swagger/swagger-ui.html new file mode 100644 index 000000000..0e7e8e60a --- /dev/null +++ b/swagger/swagger-ui.html @@ -0,0 +1,26 @@ + + + + Swagger UI + + + +
+ + + + + diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml new file mode 100644 index 000000000..326987015 --- /dev/null +++ b/swagger/swagger.yaml @@ -0,0 +1,761 @@ +openapi: 3.0.0 +info: + title: Aergo Web3 + description: Aergo Web3 API + version: 0.1.0 +servers: + - url: http://localhost/v1 +tags: + - name: Account + description: Blockchain related operations + - name: Block + description: Block related operations + - name: Transaction + description: Transaction related operations + - name: Etc + description: Etc related operations +paths: + /getAccounts: + get: + summary: 연결된 노드에 저장된 모든 계정 조회 + tags: [Account] + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getState: + get: + summary: 현재 잔액 및 Nonce 포함한 계정 상태 조회 + tags: [Account] + parameters: + - name: account + in: query + required: true + description: 조회할 계정의 주소 + schema: + type: string + example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getProof: + get: + summary: 계정의 상태와 Merkle Proof를 포함하여 조회 + tags: [Account] + parameters: + - name: account + in: query + required: true + schema: + type: string + example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + - name: root + in: query + schema: + type: string + - name: compressed + in: query + required: true + schema: + type: boolean + example: true + responses: + "200": + description: Successful response + content: + application/json: + example: + proofKey: "4ki3xLRp8xJDttIL9KgjoQkP4AA025TP2Qf1Dm0t55M=" + proofVal: "67rvGuYueuLnut1L40fXb/4DhgxGQBy74GJGrReJerg=" + auditPath: + [ + "LLP7wU6/v1XBrVZOqIDR6y2M+nWomqm21POat5mkT/g=", + "AA==", + "AA==", + "uFrjYteNr2Hu52deqovW4V9RHSpjMn1LDM8Fg6sRZLk=", + "DbtsQctnrKXJX5I/0yFw4peck9MSFzl98c4mWqqUmi8=", + ] + /getNameInfo: + get: + summary: 계정 이름 조회 + tags: [Account] + parameters: + - name: name + in: query + schema: + type: string + example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + - name: number + in: query + schema: + type: int + responses: + "200": + description: Successful response + content: + application/json: + example: + name: + name: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + /getBalance: + get: + summary: 특정 주소의 잔액을 조회 + tags: [Account] + parameters: + - name: account + required: true + in: query + schema: + type: string + example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + responses: + "200": + description: Successful response + content: + application/json: + example: + balance: "1000000000000000000" + /getBlock: + get: + summary: 블록의 정보를 조회 + tags: [Block] + parameters: + - name: hash + in: query + schema: + type: string + - name: number + in: query + schema: + type: integer + example: 1 + responses: + "200": + description: Successful response + content: + application/json: + example: + hash: "C0pxUo0dljwDELyLG9lijEdmBjOOH9XNsfPfGMQ0pmA=" + header: + chainID: "AwAAAAAAYm10LmFlcmdvLmlvL3JhZnQ=" + prevBlockHash: "lK4dq/zpT/Y8cSSdebJY9j8FmGJHjKG4SJF4r4++a8E=" + blockNo: 1 + timestamp: 1692154145436345000 + blocksRootHash: "4YQSYp0dkqUHYzTLAciMW9ZDc3RU89VMYuFBpfyHxaQ=" + txsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + receiptsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + pubKey: "CAISIQNmmKv+inhXk+dWY2XdX8MxkZk7SCxlBoXSrAaYKsweFQ==" + sign: "MEQCIAu7xj6QIBKM+IfSLQho+b1l3fHXhxWYbpxC9ZnfLT2pAiAEbSmG7oeRGSfkWW96xAuaAZri9tlx4LD/eZNS9mQzlw==" + body: {} + /getBlockNumber: + get: + summary: 가장 최근 블록의 번호를 조회 + tags: [Block] + responses: + "200": + description: Successful response + content: + application/json: + example: + best_block_hash: "OxnydGsA8B0VFcKOM09cq3qOlyZjkr10Zz9yUYR0eWg=" + best_height: 491 + consensus_info: '{"Type":"raft","Status":{"Leader":"local1","Total":3,"Name":"local1","RaftId":"6d3862958785a554","Status":null}}' + best_chain_id_hash: "mhY5TnCy9Uv4X9mQCk0ad0jdUqGMrX05oixwJBvQnH0=" + chain_info: + id: + magic: "bmt.aergo.io" + consensus: "raft" + version: 3 + bpNumber: 3 + maxblocksize: 1000400 + maxtokens: "AkMGxAl4WcQ8AAAA" + gasprice: "C6Q7dAA=" + nameprice: "DeC2s6dkAAA=" + /getBlockBody: + get: + summary: 블록안의 트랜잭션 조회 + tags: [Block] + parameters: + - name: hash + in: query + schema: + type: string + example: "" + - name: number + in: query + require: true + schema: + type: integer + example: 1 + - name: offset + in: query + require: true + schema: + type: integer + example: 1 + - name: size + in: query + require: true + schema: + type: integer + example: 5 + responses: + "200": + description: Successful response + content: + application/json: + example: + offset: 1, + size: 5, + body: {} + /listBlockHeaders: + get: + summary: 주어진 블록에서 시작하여 마지막 n개의 블록 검색 + tags: [Block] + parameters: + - name: height + in: query + require: true + schema: + type: integer + example: 1 + - name: size + in: query + require: true + schema: + type: integer + example: 5 + - name: offset + in: query + require: true + schema: + type: integer + example: 1 + - name: asc + in: query + require: true + schema: + type: bool + example: true + responses: + "200": + description: Successful response + content: + application/json: + example: + blocks: + - hash: "lK4dq/zpT/Y8cSSdebJY9j8FmGJHjKG4SJF4r4++a8E=" + header: + chainID: "AwAAAAAAYm10LmFlcmdvLmlvL3JhZnQ=" + timestamp: 1559883600000000000 + blocksRootHash: "4YQSYp0dkqUHYzTLAciMW9ZDc3RU89VMYuFBpfyHxaQ=" + txsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + receiptsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + /getBlockMetadata: + get: + summary: 블록 메타데이터를 검색 + tags: [Block] + parameters: + - name: hash + in: query + schema: + type: string + - name: number + in: query + schema: + type: integer + example: 1 + responses: + "200": + description: Successful response + content: + application/json: + example: + hash: "A7L0SFNlkIAGivGOMKyzQIeaIbIZzUN0KiB/XZzzyRU=" + header: + chainID: "AwAAAAAAYm10LmFlcmdvLmlvL3JhZnQ=" + prevBlockHash: "lK4dq/zpT/Y8cSSdebJY9j8FmGJHjKG4SJF4r4++a8E=" + blockNo: 1 + timestamp: 1692161210463122000 + blocksRootHash: "4YQSYp0dkqUHYzTLAciMW9ZDc3RU89VMYuFBpfyHxaQ=" + txsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + receiptsRootHash: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + pubKey: "CAISIQNmmKv+inhXk+dWY2XdX8MxkZk7SCxlBoXSrAaYKsweFQ==" + sign: "MEUCIQC1ZOHY2Yi1tMl6zi4uvM5Rd2Mo+JAmlzYBNFd9hC7aRQIgbR+b5bhz06OBElZaiMt60gQK6KakgQjDZvomSRPIWEM=" + size: 324 + /getTransaction: + get: + summary: 트랜잭션의 정보 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getTransactionReceipt: + get: + summary: 트랜잭션의 영수증 정보를 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getBlockTX: + get: + summary: 트랜잭션 해시로 조회한 블록 내의 트랜잭션에 대한 정보 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /verifyTX: + get: + summary: 트랜잭션의 유효성 검증 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + - name: nonce + in: query + schema: + type: integer + - name: account + in: query + schema: + type: string + - name: recipient + in: query + schema: + type: string + - name: amount + in: query + schema: + type: string + - name: payload + in: query + schema: + type: string + - name: gasLimit + in: query + schema: + type: integer + - name: gasPrice + in: query + schema: + type: string + - name: type + in: query + schema: + type: integer + - name: chainIdHash + in: query + schema: + type: string + - name: sign + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /sendSignedTransaction: + post: + summary: 서명된 트랜잭션을 커밋 + tags: [Transaction] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + signedTransaction: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /call: + get: + summary: 스마트 컨트랙트의 상태 조회 + tags: [Transaction] + parameters: + - name: contractAddress + in: query + schema: + type: string + - name: queryinfo + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getPastEvents: + get: + summary: 지난 이벤트를 조회 + tags: [Transaction] + parameters: + - name: contractAddress + in: query + schema: + type: string + - name: eventName + in: query + schema: + type: string + - name: blockfrom + in: query + schema: + type: integer + - name: blockto + in: query + schema: + type: integer + - name: desc + in: query + schema: + type: boolean + - name: argFilter + in: query + schema: + type: string + - name: recentBlockCnt + in: query + schema: + type: integer + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getABI: + get: + summary: ABI 조회 + tags: [Transaction] + parameters: + - name: address + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /queryContractState: + get: + summary: 스마트컨트랙트 상태 조회 (현재 저장값 조회용) + tags: [Transaction] + parameters: + - name: address + in: query + schema: + type: string + - name: root + in: query + schema: + type: string + - name: compressed + in: query + schema: + type: boolean + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getBlockTransactionCount: + get: + summary: 블록안의 트랜잭션 개수를 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + - name: number + in: query + schema: + type: integer + responses: + "200": + description: Successful response + content: + application/json: + example: + transactionCount: 10 + /getTransactionCount: + get: + summary: 주소에서 발생한 트랜잭션 개수를 조회 + tags: [Transaction] + parameters: + - name: address + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + transactionCount: 20 + /getBlockTransactionReceipts: + get: + summary: 블록에 포함된 트랜잭션 영수증(Receipt)들을 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + - name: number + in: query + schema: + type: integer + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getChainInfo: + get: + summary: 블록체인의 현재 상태 조회 + tags: [Etc] + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getConsensusInfo: + get: + summary: Consensus 정보 조회 + tags: [Etc] + responses: + "200": + description: Successful response + content: + application/json: + example: + consensusAlgorithm: "PoA" + blockTime: 5 + /getAccountVotes: + get: + summary: 가장 많이 투표된 블록 생산자 또는 시스템 변수 조회 + tags: [Etc] + parameters: + - name: account + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + votes: + - producer: "0x1234567890abcdef" + votesCount: 100000 + totalVotes: 5 + /getNodeInfo: + get: + summary: 노드 상태 조회 + tags: [Etc] + parameters: + - name: timeout + in: query + schema: + type: array + items: + type: byte + - name: component + in: query + schema: + type: array + items: + type: byte + responses: + "200": + description: Successful response + content: + application/json: + example: + nodeName: "MyNode" + nodeVersion: "1.2.3" + /getChainId: + get: + summary: 연결된 노드의 피어 목록 조회 + tags: [Etc] + parameters: + - name: noHidden + in: query + schema: + type: boolean + - name: showSelf + in: query + schema: + type: boolean + responses: + "200": + description: Successful response + content: + application/json: + example: + peers: + - peerId: "abc123" + chainId: 12345 + totalPeers: 5 + /getServerInfo: + get: + summary: 서버 정보 반환 + tags: [Etc] + parameters: + - name: key + in: query + schema: + type: array + items: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + serverName: "MyServer" + serverVersion: "2.0.1" + /getStaking: + get: + summary: 스테이킹 정보 반환 + tags: [Etc] + parameters: + - name: account + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + stakingInfo: + account: "0x1234567890abcdef" + stakedAmount: "1000000000000000000" + /getVotes: + get: + summary: 투표에 대한 상위 결과 반환 + tags: [Etc] + parameters: + - name: id + in: query + schema: + type: string + - name: count + in: query + schema: + type: integer + responses: + "200": + description: Successful response + content: + application/json: + example: + votes: + - producer: "0x1234567890abcdef" + votesCount: 100000 + totalCount: 5 + /metric: + get: + summary: 노드 메트릭스를 반환 + tags: [Etc] + parameters: + - name: type + in: query + schema: + type: string + enum: ["NOTHING", "P2P_NETWORK"] + example: "P2P_NETWORK" + responses: + "200": + description: Successful response + content: + application/json: + example: {} + /getEnterpriseConfig: + get: + summary: 엔터프라이즈(기업용) 구성 설정 조회 + tags: [Etc] + parameters: + - name: key + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + configKey: "enterprise" + configValue: "enabled" + /getConfChangeProgress: + get: + summary: requestID로 조회한 changeCluster 트랜잭션의 상태 조회 + tags: [Etc] + parameters: + - name: hash + in: query + schema: + type: string + responses: + "200": + description: Successful response + content: + application/json: + example: + progress: + requestID: "abcd1234" + status: "completed" From e2086ffe31932337e64064bd156499db8cda7605 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Mon, 28 Aug 2023 20:26:18 +0900 Subject: [PATCH 003/134] rpc api add --- rpc/web3/v1.go | 912 +++++++++++++++++++++++++++++++++++++++---- rpc/web3/web3.go | 18 + swagger/swagger.yaml | 591 +++++++++++++++++++++++----- 3 files changed, 1336 insertions(+), 185 deletions(-) diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index aaa4b0871..0accb5dd2 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -1,20 +1,24 @@ package web3 import ( + "bytes" "crypto/sha256" "encoding/base64" "encoding/binary" + "encoding/json" + "fmt" + "io/ioutil" "net/http" "net/url" "strconv" "strings" + "github.com/aergoio/aergo/cmd/aergocli/util" + "github.com/aergoio/aergo/internal/common" "github.com/aergoio/aergo/rpc" "github.com/aergoio/aergo/types" "github.com/asaskevich/govalidator" "github.com/mr-tron/base58" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type Web3APIv1 struct { @@ -44,22 +48,29 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok case "/getState": return api.GetState(); case "/getProof": return api.GetStateAndProof(); case "/getNameInfo": return api.GetNameInfo(); + case "/getBalance": return api.GetBalance(); case "/getBlock": return api.GetBlock(); case "/getBlockNumber": return api.Blockchain(); case "/getBlockBody": return api.GetBlockBody(); case "/listBlockHeaders": return api.ListBlockHeaders(); case "/getBlockMetadata": return api.GetBlockMetadata(); - case "/getChainInfo": return api.GetChainInfo(); - case "/getConsencusInfo": return api.GetConsensusInfo(); + case "/getTransaction": return api.GetTX(); case "/getTransactionReceipt": return api.GetReceipt(); case "/getBlockTX": return api.GetBlockTX(); - case "/verifyTX": return api.VerifyTX(); - case "/call": return api.QueryContract(); + case "/verifyTX": return api.VerifyTX(); // test + case "/call": return api.QueryContract(); // test case "/getPastEvents": return api.ListEvents(); case "/getABI": return api.GetABI(); - case "/getAccountVotes": return api.GetAccountVotes(); case "/queryContractState": return api.QueryContractState(); + + case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); + // case "/getTransactionCount": return api.GetTransactionCount(); + // case "/getBlockTransactionReceipts": return api.GetBlockTransactionReceipts(); + + case "/getChainInfo": return api.GetChainInfo(); + case "/getConsensusInfo": return api.GetConsensusInfo(); + case "/getAccountVotes": return api.GetAccountVotes(); case "/getNodeInfo": return api.NodeState(); case "/getChainId": return api.GetPeers(); case "/getServerInfo": return api.GetServerInfo(); @@ -69,75 +80,102 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); case "/getConfChangeProgress": return api.GetConfChangeProgress(); - // case "/getBalance": return api.GetBalance(); - // case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); - // case "/getTransactionCount": return api.GetTransactionCount(); - // case "/getBlockTransactionReceipts": return api.GetBlockTransactionReceipts(); - case "/ChainStat": return api.ChainStat(); + + + case "/chainStat": return api.ChainStat(); case "/ListBlockMetadata": return api.ListBlockMetadata(); default: return nil, false } } else if r.Method == http.MethodPost { switch path { - case "/sendSignedTransaction": return api.CommitTX(); + case "/sendSignedTransaction": return api.CommitTX(); // test default: return nil, false } } return nil, false } -func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { + request := &types.Empty{} + return commonResponseHandler(api.rpc.GetAccounts(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - // Params - request := &types.MetricsRequest{} - metricType := values.Get("type") - if metricType != "" { - request.Types = append(request.Types, types.MetricType(types.MetricType_value[metricType])) + request := &types.SingleBytes{} + account := values.Get("account") + if account != "" { + accountBytes, err := types.DecodeAddress(account) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = accountBytes } - - // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.Metric(api.request.Context(), request)), true -} - -func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(api.rpc.GetAccounts(api.request.Context(), request)), true + msg, err := api.rpc.GetState(api.request.Context(), request); + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + balance, err := util.ConvertUnit(msg.GetBalanceBigInt(), "aergo") + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := fmt.Sprintf(`{"account":"%s", "balance":"%s", "nonce":%d}`, account, balance, msg.GetNonce()) + return stringResponseHandler(result, nil), true } -func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - // Params - request := &types.SingleBytes{} + request := &types.AccountAndRoot{} account := values.Get("account") if account != "" { - request.Value = []byte(account) + accountBytes, err := types.DecodeAddress(account) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Account = accountBytes } - // Validate + compressed := values.Get("compressed") + if compressed != "" { + compressedValue, parseErr := strconv.ParseBool(compressed) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Compressed = compressedValue + } + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetState(api.request.Context(), request)), true -} - -func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { - request := &types.AccountAndRoot{} - return commonResponseHandler(api.rpc.GetStateAndProof(api.request.Context(), request)), true + msg, err := api.rpc.GetStateAndProof(api.request.Context(), request); + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + balance, err := util.ConvertUnit(msg.GetState().GetBalanceBigInt(), "aergo") + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := fmt.Sprintf(`{"account":"%s", "nonce":%d, "balance":"%s", "included":%t, "merkle proof length":%d, "height":%d}`+"\n", + account, msg.GetState().GetNonce(), balance, msg.GetInclusion(), len(msg.GetAuditPath()), msg.GetHeight()) + return stringResponseHandler(result, nil), true } func (api *Web3APIv1) GetNameInfo() (handler http.Handler, ok bool) { @@ -166,20 +204,58 @@ func (api *Web3APIv1) GetNameInfo() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetNameInfo(api.request.Context(), request)), true + msg, err := api.rpc.GetNameInfo(api.request.Context(), request); + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := fmt.Sprintf(`{"%s": {"Owner" : "%s", "Destination" : "%s" }}`, + msg.Name.Name, types.EncodeAddress(msg.Owner), types.EncodeAddress(msg.Destination)) + + return stringResponseHandler(result, nil), true } -func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetBalance() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } + request := &types.SingleBytes{} + account := values.Get("account") + if account != "" { + accountBytes, err := types.DecodeAddress(account) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = accountBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetState(api.request.Context(), request); + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := fmt.Sprintf(`{"balance":"%s"}`, msg.GetBalanceBigInt()) + return stringResponseHandler(result, nil), true +} + + +func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + // Params request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { - hashBytes, err := base64.StdEncoding.DecodeString(hash) + hashBytes, err := base58.Decode(hash) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -207,6 +283,57 @@ func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.GetBlock(api.request.Context(), request)), true } +func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base58.Decode(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + + number := values.Get("number") + if number != "" { + numberValue, err := strconv.ParseUint(number, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + number := uint64(numberValue) // Replace with your actual value + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, number) + request.Value = byteValue + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetBlock(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := fmt.Sprintf(`{"count":"%d"}`, func() int { + if msg.Body.Txs != nil { + return len(msg.Body.Txs) + } + return 0 + }()) + + return stringResponseHandler(result, nil), true +} + + func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { ca := api.rpc.GetActorHelper().GetChainAccessor() last, err := ca.GetBestBlock() @@ -245,7 +372,7 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { hash := values.Get("hash") if hash != "" { - hashBytes, err := base64.StdEncoding.DecodeString(hash) + hashBytes, err := base58.Decode(hash) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -353,7 +480,7 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { - hashBytes, err := base64.StdEncoding.DecodeString(hash) + hashBytes, err := base58.Decode(hash) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -382,8 +509,52 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { } func (api *Web3APIv1) ListBlockMetadata() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.ListParams{} + height := values.Get("height") + if height != "" { + heightValue, parseErr := strconv.ParseUint(height, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Height = heightValue + } + + size := values.Get("size") + if size != "" { + sizeValue, parseErr := strconv.ParseUint(size, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Size = uint32(sizeValue) + } + + offset := values.Get("offset") + if offset != "" { + offsetValue, parseErr := strconv.ParseUint(offset, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Offset = uint32(offsetValue) + } + + asc := values.Get("asc") + if asc != "" { + ascValue, parseErr := strconv.ParseBool(asc) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Asc = ascValue + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + return commonResponseHandler(api.rpc.ListBlockMetadata(api.request.Context(), request)), true } @@ -409,7 +580,6 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - // Params request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { @@ -420,7 +590,6 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { request.Value = hashBytes } - // Validate if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -428,68 +597,639 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { } func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base58.Decode(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetTX(api.request.Context(), request) + if err == nil { + return commonResponseHandler(util.ConvTxEx(msg, util.Base58), nil), true + } else { + msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) + + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + return commonResponseHandler(util.ConvTxInBlockEx(msgblock, util.Base58), nil), true + } + } + func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base58.Decode(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetTX(api.request.Context(), request) + if err == nil { + return commonResponseHandler(util.ConvTxEx(msg, util.Base58), nil), true + + } else { + msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + return commonResponseHandler(util.ConvTxInBlockEx(msgblock, util.Base58), nil), true + } } + func (api *Web3APIv1) VerifyTX() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true -} -func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true -} -func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true -} -func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.Tx{} + request.Body = &types.TxBody{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base64.StdEncoding.DecodeString(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Hash = hashBytes + } + + nonce := values.Get("nonce") + if nonce != "" { + nonceValue, parseErr := strconv.ParseUint(nonce, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Body.Nonce = nonceValue + } + + account := values.Get("account") + if account != "" { + request.Body.Account = []byte(account) + } + + recipient := values.Get("recipient") + if recipient != "" { + recipientBytes, err := base64.StdEncoding.DecodeString(recipient) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Body.Recipient = recipientBytes + } + + amount := values.Get("amount") + if amount != "" { + request.Body.Amount = []byte(amount) + } + + payload := values.Get("payload") + if payload != "" { + request.Body.Payload = []byte(payload) + } + + gasLimit := values.Get("gasLimit") + if gasLimit != "" { + gasLimitValue, parseErr := strconv.ParseUint(gasLimit, 10, 64) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Body.GasLimit = gasLimitValue + } + + gasPrice := values.Get("gasPrice") + if gasPrice != "" { + request.Body.GasPrice = []byte(gasPrice) + } + + txType := values.Get("type") + if txType != "" { + request.Body.Type = types.TxType(types.TxType_value[txType]) + } + + chainIdHash := values.Get("chainIdHash") + if hash != "" { + chainIdHashBytes, err := base64.StdEncoding.DecodeString(chainIdHash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Body.ChainIdHash = chainIdHashBytes + } + + sign := values.Get("sign") + if sign != "" { + signBytes, err := base64.StdEncoding.DecodeString(sign) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Body.Sign = signBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.VerifyTX(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + + } + if msg.Tx != nil { + return commonResponseHandler(util.TxConvBase58Addr(msg.Tx), nil), true + } else { + return commonResponseHandler(&types.Empty{}, nil), true + } +} + +func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.Query{} + address := values.Get("address") + if address != "" { + hashBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.ContractAddress = hashBytes + } + + var ci types.CallInfo + name := values.Get("name") + if name != "" { + ci.Name = name + } + + query := values.Get("query") + if query != "" { + json.Unmarshal([]byte(query), &ci.Args) + } + + callinfo, err := json.Marshal(ci) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Queryinfo = callinfo; + + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.QueryContract(api.request.Context(), request)), true } + +func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.FilterInfo{} + address := values.Get("address") + if address != "" { + hashBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.ContractAddress = hashBytes + } + + EventName := values.Get("EventName") + if EventName != "" { + request.EventName = EventName + } + + Blockfrom := values.Get("Blockfrom") + if Blockfrom != "" { + BlockfromValue, err := strconv.ParseUint(Blockfrom, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Blockfrom = uint64(BlockfromValue) + } + + Blockto := values.Get("Blockto") + if Blockto != "" { + BlocktoValue, err := strconv.ParseUint(Blockto, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Blockto = uint64(BlocktoValue) + } + + desc := values.Get("desc") + if desc != "" { + descValue, parseErr := strconv.ParseBool(desc) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Desc = descValue + } + + argFilter := values.Get("argFilter") + if argFilter != "" { + request.ArgFilter = []byte(argFilter) + } + + recentBlockCnt := values.Get("recentBlockCnt") + if recentBlockCnt != "" { + recentBlockCntValue, parseErr := strconv.ParseInt(recentBlockCnt, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.RecentBlockCnt = int32(recentBlockCntValue) + }else{ + request.RecentBlockCnt = 0 + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.ListEvents(api.request.Context(), request)), true +} + +func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.SingleBytes{} + address := values.Get("address") + if address != "" { + hashBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetABI(api.request.Context(), request)), true +} + func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.AccountAddress{} + address := values.Get("address") + if address != "" { + hashBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetAccountVotes(api.request.Context(), request)), true } + func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.StateQuery{} + address := values.Get("address") + if address != "" { + addressBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.ContractAddress = addressBytes + } + + storageKeyPlain := bytes.NewBufferString("_sv_") + args1 := values.Get("varname1") + if args1 != "" { + storageKeyPlain.WriteString(args1) + } + args2 := values.Get("varname2") + if args2 != "" { + storageKeyPlain.WriteString("-") + storageKeyPlain.WriteString(args2) + } + + storageKey := common.Hasher([]byte(storageKeyPlain.Bytes())) + request.StorageKeys = [][]byte{storageKey} + + compressed := values.Get("compressed") + if compressed != "" { + compressedValue, parseErr := strconv.ParseBool(compressed) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Compressed = compressedValue + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.QueryContractState(api.request.Context(), request)), true } + func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.NodeReq{} + component := values.Get("component") + if component != "" { + request.Component = []byte(component) + } + + timeout := values.Get("timeout") + if timeout != "" { + timeoutValue, err := strconv.ParseUint(timeout, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + timeout := uint64(timeoutValue) // Replace with your actual value + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, timeout) + request.Timeout = byteValue + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.NodeState(api.request.Context(), request) + + return stringResponseHandler(string(msg.Value), nil), true } + func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.PeersParams{} + noHidden := values.Get("noHidden") + if noHidden != "" { + noHiddenValue, parseErr := strconv.ParseBool(noHidden) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.NoHidden = noHiddenValue + } + + showSelf := values.Get("showSelf") + if showSelf != "" { + showSelfValue, parseErr := strconv.ParseBool(showSelf) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.ShowSelf = showSelfValue + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetPeers(api.request.Context(), request)), true } + func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.KeyParams{} + keys := values["key"] + if len(keys) > 0 { + request.Key = keys + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetServerInfo(api.request.Context(), request)), true } + func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.AccountAddress{} + address := values.Get("address") + if address != "" { + addressBytes, err := types.DecodeAddress(address) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = addressBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.GetStaking(api.request.Context(), request)), true } -func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + +func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.VoteParams{} + request.Id = types.OpvoteBP.ID() + + count := values.Get("count") + if count != "" { + sizeValue, parseErr := strconv.ParseUint(count, 10, 32) + if parseErr != nil { + return commonResponseHandler(&types.Empty{}, parseErr), true + } + request.Count = uint32(sizeValue) + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetVotes(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + result := "[" + comma := "," + for i, r := range msg.GetVotes() { + result = result + "{\"" + base58.Encode(r.Candidate) + "\":" + r.GetAmountBigInt().String() + "}" + if i+1 == len(msg.GetVotes()) { + comma = "" + } + result = result + comma + } + result = result + "]" + + return stringResponseHandler(result, nil), true +} + +func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.MetricsRequest{} + metricType := values.Get("type") + if metricType != "" { + request.Types = append(request.Types, types.MetricType(types.MetricType_value[metricType])) + } + + // Validate + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return commonResponseHandler(api.rpc.Metric(api.request.Context(), request)), true } + func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.EnterpriseConfigKey{} + + key := values.Get("key") + if key != "" { + request.Key = key + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + msg, err := api.rpc.GetEnterpriseConfig(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + type outConf struct { + Key string + On *bool + Values []string + } + + var out outConf + out.Key = msg.Key + out.Values = msg.Values + if strings.ToUpper(key) != "PERMISSIONS" { + out.On = &msg.On + } + + return stringResponseHandler(util.B58JSON(out), nil), true } + func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base64.StdEncoding.DecodeString(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + block, err := api.rpc.GetBlock(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, block.BlockNo()) + + return commonResponseHandler(api.rpc.GetConfChangeProgress(api.request.Context(), &types.SingleBytes{Value: b})), true } func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { - request := &types.Empty{} - return commonResponseHandler(request, status.Errorf(codes.Unknown, "Preparing")), true + body, err := ioutil.ReadAll(api.request.Body) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + // Params + request := &types.TxBody{} + if err := json.Unmarshal(body, request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + tx := &types.Tx{Body: request} + txs := []*types.Tx{tx} + return commonResponseHandler(api.rpc.CommitTX(api.request.Context(), &types.TxList{Txs: txs})), true } diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index ec9120e91..6c5792dfa 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -78,3 +78,21 @@ func commonResponseHandler(response interface{}, err error) http.Handler { }) } +func stringResponseHandler(response string, err error) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // jsonResponse, err := json.Marshal(response) + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(response)) + }) +} + diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index 326987015..118cf3826 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -42,7 +42,10 @@ paths: description: Successful response content: application/json: - example: {} + example: + account: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + balance: "100000000 aergo" + nonce: 0 /getProof: get: summary: 계정의 상태와 Merkle Proof를 포함하여 조회 @@ -54,10 +57,6 @@ paths: schema: type: string example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" - - name: root - in: query - schema: - type: string - name: compressed in: query required: true @@ -70,16 +69,12 @@ paths: content: application/json: example: - proofKey: "4ki3xLRp8xJDttIL9KgjoQkP4AA025TP2Qf1Dm0t55M=" - proofVal: "67rvGuYueuLnut1L40fXb/4DhgxGQBy74GJGrReJerg=" - auditPath: - [ - "LLP7wU6/v1XBrVZOqIDR6y2M+nWomqm21POat5mkT/g=", - "AA==", - "AA==", - "uFrjYteNr2Hu52deqovW4V9RHSpjMn1LDM8Fg6sRZLk=", - "DbtsQctnrKXJX5I/0yFw4peck9MSFzl98c4mWqqUmi8=", - ] + account: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + nonce: 0 + balance: "100000000 aergo" + included: true + merkle proof length: 4 + height: /getNameInfo: get: summary: 계정 이름 조회 @@ -100,8 +95,9 @@ paths: content: application/json: example: - name: - name: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" + AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj: + Owner: "" + Destination: "" /getBalance: get: summary: 특정 주소의 잔액을 조회 @@ -302,7 +298,28 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "TxIdx": + { + "BlockHash": "Dss9zEetcSJy8tr7uLxUr9C8LLjLj5XQYZsfkm7jp1sa", + "Idx": 0, + }, + "Tx": + { + "Hash": "8EiUrFKE2ivrmbP21iAusiuHUViVdJPwqLgX2byZuRN1", + "Body": + { + "Nonce": 1, + "Account": "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj", + "Recipient": "AmQ2tS46doLfqsH4vy7PXmvGn7paec8wgqPWmGrcJKiLZADrJcME", + "Amount": "1000000000000000000", + "Type": 4, + "ChainIdHash": "BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn", + "Sign": "AN1rKvtRfKap2yDrBAp3gefs2YyS362oTCWPQk1oEYVwsyRm4MfMDtvbAPazr5NPBBP9TJHda8yzCXQXz2hnzrc5WRoaWBxqd", + }, + }, + } /getTransactionReceipt: get: summary: 트랜잭션의 영수증 정보를 조회 @@ -317,7 +334,22 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "BlockNo": 18, + "BlockHash": "Dss9zEetcSJy8tr7uLxUr9C8LLjLj5XQYZsfkm7jp1sa", + "contractAddress": "AmQ2tS46doLfqsH4vy7PXmvGn7paec8wgqPWmGrcJKiLZADrJcME", + "status": "SUCCESS", + "ret": {}, + "txHash": "8EiUrFKE2ivrmbP21iAusiuHUViVdJPwqLgX2byZuRN1", + "txIndex": 0, + "from": "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj", + "to": "AmQ2tS46doLfqsH4vy7PXmvGn7paec8wgqPWmGrcJKiLZADrJcME", + "feeUsed": 0, + "gasUsed": 0, + "feeDelegation": false, + "events": [], + } /getBlockTX: get: summary: 트랜잭션 해시로 조회한 블록 내의 트랜잭션에 대한 정보 조회 @@ -332,7 +364,28 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "TxIdx": + { + "BlockHash": "4KXLCU5KVgZE9oP96CVoeM3VFb5Tcu2PNCoZGYW2dRtc", + "Idx": 0, + }, + "Tx": + { + "Hash": "8EiUrFKE2ivrmbP21iAusiuHUViVdJPwqLgX2byZuRN1", + "Body": + { + "Nonce": 1, + "Account": "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj", + "Recipient": "AmQ2tS46doLfqsH4vy7PXmvGn7paec8wgqPWmGrcJKiLZADrJcME", + "Amount": "1000000000000000000", + "Type": 4, + "ChainIdHash": "BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn", + "Sign": "AN1rKvtRfKap2yDrBAp3gefs2YyS362oTCWPQk1oEYVwsyRm4MfMDtvbAPazr5NPBBP9TJHda8yzCXQXz2hnzrc5WRoaWBxqd", + }, + }, + } /verifyTX: get: summary: 트랜잭션의 유효성 검증 @@ -373,7 +426,18 @@ paths: - name: type in: query schema: - type: integer + type: string + enum: + [ + "NORMAL", + "GOVERNANCE", + "REDEPLOY", + "FEEDELEGATION", + "TRANSFER", + "CALL", + "DEPLOY", + ] + example: "NORMAL" - name: chainIdHash in: query schema: @@ -401,6 +465,36 @@ paths: properties: signedTransaction: type: string + hash: + type: string + nonce: + type: integer + account: + type: string + recipient: + type: string + amount: + type: string + payload: + type: string + gasLimit: + type: integer + gasPrice: + type: string + type: + type: string + enum: + - "NORMAL" + - "GOVERNANCE" + - "REDEPLOY" + - "FEEDELEGATION" + - "TRANSFER" + - "CALL" + - "DEPLOY" + chainIdHash: + type: string + sign: + type: string responses: "200": description: Successful response @@ -412,14 +506,21 @@ paths: summary: 스마트 컨트랙트의 상태 조회 tags: [Transaction] parameters: - - name: contractAddress + - name: address + in: query + schema: + type: string + example: AmgRLghGjbbWsPm4CZqaJEtxRdv3f5navmhVwn8phpXa7FyQBH6e + - name: name in: query schema: type: string - - name: queryinfo + example: get_value + - name: query in: query schema: type: string + example: { "key": "name" } responses: "200": description: Successful response @@ -431,7 +532,7 @@ paths: summary: 지난 이벤트를 조회 tags: [Transaction] parameters: - - name: contractAddress + - name: address in: query schema: type: string @@ -443,14 +544,17 @@ paths: in: query schema: type: integer + example: 0 - name: blockto in: query schema: type: integer + example: 0 - name: desc in: query schema: type: boolean + example: false - name: argFilter in: query schema: @@ -459,6 +563,7 @@ paths: in: query schema: type: integer + example: 0 responses: "200": description: Successful response @@ -489,7 +594,11 @@ paths: in: query schema: type: string - - name: root + - name: varname1 + in: query + schema: + type: string + - name: varname2 in: query schema: type: string @@ -502,7 +611,17 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "contractProof": + { + "key": "Qgw+1I9p/nXaN8M1izpuXapIXs04nV1JR0+NtnXiLIazyCPt8Ac=", + "proofKey": "B9a8HHz3U62tm8+6SrVPp7Ic7fFSJxDnxPxpT9UjkO0=", + "proofVal": "67rvGuYueuLnut1L40fXb/4DhgxGQBy74GJGrReJerg=", + "auditPath": + ["bTxu9o0zPDGZdyb3Lyvd2R5FSmDVtnIKA92I6IrL+Ws="], + }, + } /getBlockTransactionCount: get: summary: 블록안의 트랜잭션 개수를 조회 @@ -523,41 +642,41 @@ paths: application/json: example: transactionCount: 10 - /getTransactionCount: - get: - summary: 주소에서 발생한 트랜잭션 개수를 조회 - tags: [Transaction] - parameters: - - name: address - in: query - schema: - type: string - responses: - "200": - description: Successful response - content: - application/json: - example: - transactionCount: 20 - /getBlockTransactionReceipts: - get: - summary: 블록에 포함된 트랜잭션 영수증(Receipt)들을 조회 - tags: [Transaction] - parameters: - - name: hash - in: query - schema: - type: string - - name: number - in: query - schema: - type: integer - responses: - "200": - description: Successful response - content: - application/json: - example: {} + # /getTransactionCount: + # get: + # summary: 주소에서 발생한 트랜잭션 개수를 조회 + # tags: [Transaction] + # parameters: + # - name: address + # in: query + # schema: + # type: string + # responses: + # "200": + # description: Successful response + # content: + # application/json: + # example: + # transactionCount: 20 + # /getBlockTransactionReceipts: + # get: + # summary: 블록에 포함된 트랜잭션 영수증(Receipt)들을 조회 + # tags: [Transaction] + # parameters: + # - name: hash + # in: query + # schema: + # type: string + # - name: number + # in: query + # schema: + # type: integer + # responses: + # "200": + # description: Successful response + # content: + # application/json: + # example: {} /getChainInfo: get: summary: 블록체인의 현재 상태 조회 @@ -567,7 +686,16 @@ paths: description: Successful response content: application/json: - example: {} + example: + id: + magic: "bmt.aergo.io" + consensus: "raft" + version: 3 + bpNumber: 3 + maxblocksize: 1000400 + maxtokens: "AkMGxAl4WcQ8AAAA" + gasprice: "C6Q7dAA=" + nameprice: "DeC2s6dkAAA=" /getConsensusInfo: get: summary: Consensus 정보 조회 @@ -578,8 +706,12 @@ paths: content: application/json: example: - consensusAlgorithm: "PoA" - blockTime: 5 + type: "raft" + info: '{"Leader":"local1","Total":3,"Name":"local1","RaftId":"6d3862958785a554","Status":{"id":"6d3862958785a554","term":7,"vote":"6d3862958785a554","commit":6,"lead":"6d3862958785a554","raftState":"StateLeader","applied":6,"progress":{"57779d37986cc00":{"match":6,"next":7,"state":"ProgressStateReplicate"},"cf615af53daf2c6b":{"match":6,"next":7,"state":"ProgressStateReplicate"},"6d3862958785a554":{"match":6,"next":7,"state":"ProgressStateProbe"}},"leadtransferee":"0"}}' + bps: + - '{"Name":"local3","RaftID":"cf615af53daf2c6b","PeerID":"16Uiu2HAkyDXhsCj63R3ufsrYaK72nFT1RLVg5upabi6WAQtJzGoM","Addr":"/ip4/192.168.3.87/tcp/37846"}' + - '{"Name":"local1","RaftID":"6d3862958785a554","PeerID":"16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac","Addr":"/ip4/192.168.3.87/tcp/7846"}' + - '{"Name":"local2","RaftID":"57779d37986cc00","PeerID":"16Uiu2HAm82vRXcL187jRhFW9jnNjueMc7bSJLdcydNWUwxeUCC2U","Addr":"/ip4/192.168.3.87/tcp/27846"}' /getAccountVotes: get: summary: 가장 많이 투표된 블록 생산자 또는 시스템 변수 조회 @@ -587,6 +719,7 @@ paths: parameters: - name: account in: query + # example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" schema: type: string responses: @@ -595,10 +728,6 @@ paths: content: application/json: example: - votes: - - producer: "0x1234567890abcdef" - votesCount: 100000 - totalVotes: 5 /getNodeInfo: get: summary: 노드 상태 조회 @@ -607,23 +736,203 @@ paths: - name: timeout in: query schema: - type: array - items: - type: byte + type: integer + example: 3 - name: component in: query schema: - type: array - items: - type: byte + type: string + example: "" responses: "200": description: Successful response content: application/json: example: - nodeName: "MyNode" - nodeVersion: "1.2.3" + { + "AccountsSvc": + { + "status": "started", + "acc_processed_msg": 1, + "msg_queue_len": 0, + "msg_latency": "46.1µs", + "error": "", + "actor": + { + "config": { "UnlockTimeout": 60 }, + "personal": true, + "totalaccounts": 0, + }, + }, + "ChainSvc": + { + "status": "started", + "acc_processed_msg": 34, + "msg_queue_len": 0, + "msg_latency": "60.242µs", + "error": "", + "actor": + { + "config": + { + "MaxBlockSize": 1000000, + "CoinbaseAccount": "", + "MaxAnchorCount": 20, + "VerifierCount": 8, + "ForceResetHeight": 0, + "ZeroFee": true, + "VerifyOnly": false, + "StateTrace": 0, + "VerifyBlock": 0, + "NumWorkers": 16, + "NumLStateClosers": 2, + "CloseLimit": 100, + }, + "orphan": 0, + "testmode": false, + "testnet": false, + }, + }, + "MemPoolSvc": + { + "status": "started", + "acc_processed_msg": 16, + "msg_queue_len": 0, + "msg_latency": "36.045µs", + "error": "", + "actor": + { + "config": + { + "ShowMetrics": false, + "EnableFadeout": false, + "FadeoutPeriod": 12, + "VerifierNumber": 32, + "DumpFilePath": "./data/mempool.dump", + }, + "dead": 0, + "orphan": 0, + "total": 0, + "whitelist": [], + "whitelist_on": false, + }, + }, + "RPCSvc": + { + "status": "started", + "acc_processed_msg": 14, + "msg_queue_len": 0, + "msg_latency": "27.18µs", + "error": "", + "actor": + { + "config": + { + "NetServiceAddr": "0.0.0.0", + "NetServicePort": 7845, + "NetServicePath": "", + "NetServiceTrace": false, + "NSEnableTLS": false, + "NSCert": "", + "NSKey": "", + "NSCACert": "", + "NSAllowCORS": false, + }, + "streams": { "block": 0, "blockMeta": 0, "event": 0 }, + "version": "v2.4.4-134-gaa1d7d30", + }, + }, + "SyncerSvc": + { + "status": "started", + "acc_processed_msg": 1, + "msg_queue_len": 0, + "msg_latency": "34.66µs", + "error": "", + "actor": + { + "block_added": 0, + "block_fetched": 0, + "end": 0, + "running": false, + "start": 0, + "total": 0, + }, + }, + "mapSvc": + { + "status": "started", + "acc_processed_msg": 1, + "msg_queue_len": 0, + "msg_latency": "58.423µs", + "error": "", + "actor": null, + }, + "p2pSvc": + { + "status": "started", + "acc_processed_msg": 18, + "msg_queue_len": 0, + "msg_latency": "66.815µs", + "error": "", + "actor": + { + "config": + { + "NetProtocolAddr": "192.168.3.87", + "NetProtocolPort": 7846, + "NPBindAddr": "0.0.0.0", + "NPBindPort": 7846, + "NPEnableTLS": false, + "NPCert": "", + "NPKey": "bmt1.key", + "NPAddPeers": null, + "NPHiddenPeers": null, + "NPDiscoverPeers": false, + "NPMaxPeers": 100, + "NPPeerPool": 100, + "NPExposeSelf": false, + "NPUsePolaris": false, + "NPAddPolarises": null, + "LogFullPeerID": false, + "PeerRole": "producer", + "Producers": null, + "InternalZones": null, + "Agent": "", + }, + "netstat": + { + "in": 35885, + "out": 26500, + "since": "2023-08-25T17:58:05.12366+09:00", + }, + "status": + { + "ID": "16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac", + "Role": "Producer", + "ProducerIDs": + [ + "16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac", + ], + "Addresses": ["/ip4/192.168.3.87/tcp/7846"], + "Version": "v2.4.4-134-gaa1d7d30", + "Hidden": true, + }, + "syncman": + { + "blocks": 0, + "transactions": + { + "backCache": 0, + "frontCache": 0, + "queryQueue": 0, + }, + }, + "whitelist": [], + "whitelist_on": false, + }, + }, + } /getChainId: get: summary: 연결된 노드의 피어 목록 조회 @@ -633,20 +942,73 @@ paths: in: query schema: type: boolean + example: false - name: showSelf in: query schema: type: boolean + example: false responses: "200": description: Successful response content: application/json: example: - peers: - - peerId: "abc123" - chainId: 12345 - totalPeers: 5 + { + "peers": + [ + { + "address": + { + "address": "192.168.3.87", + "port": 37846, + "peerID": "ACUIAhIhAjhSa/+nVg43tNhkJnaVx+xPjarZhVzd2PITk7uuJ8C0", + "role": "Producer", + "version": "v2.4.1", + "addresses": ["/ip4/192.168.3.87/tcp/37846"], + "producerIDs": + [ + "ACUIAhIhAjhSa/+nVg43tNhkJnaVx+xPjarZhVzd2PITk7uuJ8C0", + ], + }, + "bestblock": + { + "blockHash": "2Sw66KMI9ACsHxdekMnzgO422nA+3M7wlq7LGAuxDD0=", + "blockNo": 166, + }, + "state": 2, + "hidden": true, + "lashCheck": 1692954055949754000, + "version": "v2.4.1", + "acceptedRole": "Producer", + }, + { + "address": + { + "address": "192.168.3.87", + "port": 27846, + "peerID": "ACUIAhIhArtT5yoZccZO1OKI5stQRZf+h6dMC+KSg2UvdS1YY0Ep", + "role": "Producer", + "version": "v2.4.1", + "addresses": ["/ip4/192.168.3.87/tcp/27846"], + "producerIDs": + [ + "ACUIAhIhArtT5yoZccZO1OKI5stQRZf+h6dMC+KSg2UvdS1YY0Ep", + ], + }, + "bestblock": + { + "blockHash": "zr34lRpn8ZKLMaM5wBP0NVM5B8Bm+/bZo4AXUtosvWA=", + "blockNo": 118, + }, + "state": 2, + "hidden": true, + "lashCheck": 1692954008028108000, + "version": "v2.4.1", + "acceptedRole": "Producer", + }, + ], + } /getServerInfo: get: summary: 서버 정보 반환 @@ -664,8 +1026,20 @@ paths: content: application/json: example: - serverName: "MyServer" - serverVersion: "2.0.1" + { + "status": + { + "addr": "192.168.3.87", + "id": "16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac", + "port": "7846", + "version": "v2.4.4-134-gaa1d7d30", + }, + "config": + { + "account": { "props": { "unlocktimeout": "60" } }, + "base": { "props": { "personal": "true" } }, + }, + } /getStaking: get: summary: 스테이킹 정보 반환 @@ -675,24 +1049,18 @@ paths: in: query schema: type: string + example: "AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj" responses: "200": description: Successful response content: application/json: example: - stakingInfo: - account: "0x1234567890abcdef" - stakedAmount: "1000000000000000000" /getVotes: get: summary: 투표에 대한 상위 결과 반환 tags: [Etc] parameters: - - name: id - in: query - schema: - type: string - name: count in: query schema: @@ -703,10 +1071,6 @@ paths: content: application/json: example: - votes: - - producer: "0x1234567890abcdef" - votesCount: 100000 - totalCount: 5 /metric: get: summary: 노드 메트릭스를 반환 @@ -723,7 +1087,38 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "peers": + [ + { + "peerID": "ACUIAhIhArtT5yoZccZO1OKI5stQRZf+h6dMC+KSg2UvdS1YY0Ep", + "sumIn": 163708, + "avrIn": 19497, + "sumOut": 220664, + "avrOut": 26261, + }, + { + "peerID": "ACUIAhIhAjhSa/+nVg43tNhkJnaVx+xPjarZhVzd2PITk7uuJ8C0", + "sumIn": 165021, + "avrIn": 19651, + "sumOut": 221601, + "avrOut": 26367, + }, + ], + } + /chainStat: + get: + summary: 체인 통계 + tags: [Etc] + parameters: + responses: + "200": + description: Successful response + content: + application/json: + example: + report: '{"ReorgStat":{"Count":0}}' /getEnterpriseConfig: get: summary: 엔터프라이즈(기업용) 구성 설정 조회 @@ -739,8 +1134,9 @@ paths: content: application/json: example: - configKey: "enterprise" - configValue: "enabled" + Key: "" + On: false + Values: "" /getConfChangeProgress: get: summary: requestID로 조회한 changeCluster 트랜잭션의 상태 조회 @@ -756,6 +1152,3 @@ paths: content: application/json: example: - progress: - requestID: "abcd1234" - status: "completed" From 65c1f312dd9595b6a420fe6aad4060efd0b1835d Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Thu, 14 Sep 2023 08:44:15 +0900 Subject: [PATCH 004/134] Add API : getBlockTransactionReceipts --- chain/chainhandle.go | 59 +++++++++ chain/chainservice.go | 16 +++ cmd/aergocli/cmd/signtx_test.go | 6 + cmd/aergosvr/aergosvr.go | 2 +- config/types.go | 9 ++ message/blockchainmsg.go | 13 ++ rpc/grpcserver.go | 47 ++++++++ rpc/web3/v1.go | 206 +++++++++++++++++++++++++------- rpc/web3/web3.go | 13 +- swagger/swagger.yaml | 119 +++++++++++++----- types/receipt.go | 28 ++--- types/rpc.pb.go | 35 ++++++ 12 files changed, 460 insertions(+), 93 deletions(-) diff --git a/chain/chainhandle.go b/chain/chainhandle.go index 1316ff414..696fd5503 100644 --- a/chain/chainhandle.go +++ b/chain/chainhandle.go @@ -134,6 +134,65 @@ func (cs *ChainService) getReceipt(txHash []byte) (*types.Receipt, error) { return r, nil } +func (cs *ChainService) getReceipts(blockHash []byte) (*types.Receipts, error) { + block, err := cs.cdb.getBlock(blockHash) + blockInMainChain, err := cs.cdb.GetBlockByNo(block.Header.BlockNo) + if !bytes.Equal(block.BlockHash(), blockInMainChain.BlockHash()) { + return nil, errors.New("cannot find a receipt") + } + + receipts, err := cs.cdb.getReceipts(block.BlockHash(), block.GetHeader().BlockNo, cs.cfg.Hardfork) + if err != nil { + return nil, err + } + + for idx, r := range receipts.Get() { + r.SetMemoryInfo(blockHash, block.Header.BlockNo, int32(idx)) + + r.ContractAddress = types.AddressOrigin(r.ContractAddress) + + for _, tx := range block.GetBody().GetTxs() { + if bytes.Equal(r.GetTxHash(), tx.GetHash()) { + r.From = tx.GetBody().GetAccount() + r.To = tx.GetBody().GetRecipient() + break + } + } + } + + return receipts, nil +} + +func (cs *ChainService) getReceiptsByNo(blockNo types.BlockNo) (*types.Receipts, error) { + blockInMainChain, err := cs.cdb.GetBlockByNo(blockNo) + + block, err := cs.cdb.getBlock(blockInMainChain.BlockHash()) + if !bytes.Equal(block.BlockHash(), blockInMainChain.BlockHash()) { + return nil, errors.New("cannot find a receipt") + } + + receipts, err := cs.cdb.getReceipts(block.BlockHash(), block.GetHeader().BlockNo, cs.cfg.Hardfork) + if err != nil { + return nil, err + } + + for idx, r := range receipts.Get() { + r.SetMemoryInfo(blockInMainChain.BlockHash(), blockNo, int32(idx)) + + r.ContractAddress = types.AddressOrigin(r.ContractAddress) + + for _, tx := range block.GetBody().GetTxs() { + if bytes.Equal(r.GetTxHash(), tx.GetHash()) { + r.From = tx.GetBody().GetAccount() + r.To = tx.GetBody().GetRecipient() + break + } + } + } + + return receipts, nil +} + func (cs *ChainService) getEvents(events *[]*types.Event, blkNo types.BlockNo, filter *types.FilterInfo, argFilter []types.ArgFilter) uint64 { blkHash, err := cs.cdb.getHashByNo(blkNo) diff --git a/chain/chainservice.go b/chain/chainservice.go index 79f5efd56..cde64bbbb 100644 --- a/chain/chainservice.go +++ b/chain/chainservice.go @@ -179,6 +179,8 @@ type IChainHandler interface { getBlockByNo(blockNo types.BlockNo) (*types.Block, error) getTx(txHash []byte) (*types.Tx, *types.TxIdx, error) getReceipt(txHash []byte) (*types.Receipt, error) + getReceipts(blockHash []byte) (*types.Receipts, error) + getReceiptsByNo(blockNo types.BlockNo) (*types.Receipts, error) getAccountVote(addr []byte) (*types.AccountVoteInfo, error) getVotes(id string, n uint32) (*types.VoteList, error) getStaking(addr []byte) (*types.Staking, error) @@ -434,6 +436,8 @@ func (cs *ChainService) Receive(context actor.Context) { *message.GetStateAndProof, *message.GetTx, *message.GetReceipt, + *message.GetReceipts, + *message.GetReceiptsByNo, *message.GetABI, *message.GetQuery, *message.GetStateQuery, @@ -774,6 +778,18 @@ func (cw *ChainWorker) Receive(context actor.Context) { Receipt: receipt, Err: err, }) + case *message.GetReceipts: + receipts, err := cw.getReceipts(msg.BlockHash) + context.Respond(message.GetReceiptsRsp{ + Receipts: receipts, + Err: err, + }) + case *message.GetReceiptsByNo: + receipts, err := cw.getReceiptsByNo(msg.BlockNo) + context.Respond(message.GetReceiptsByNoRsp{ + Receipts: receipts, + Err: err, + }) case *message.GetABI: sdb = cw.sdb.OpenNewStateDB(cw.sdb.GetRoot()) address, err := getAddressNameResolved(sdb, msg.Contract) diff --git a/cmd/aergocli/cmd/signtx_test.go b/cmd/aergocli/cmd/signtx_test.go index bd1d56d28..4c5cfc9e3 100644 --- a/cmd/aergocli/cmd/signtx_test.go +++ b/cmd/aergocli/cmd/signtx_test.go @@ -53,3 +53,9 @@ func TestSignWithPath(t *testing.T) { os.RemoveAll(testDir) } +// aergocli signtx --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --to AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y --amount 1aergo --password bmttest +// aergocli signtx --keystore . --password bmttest --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --jsontx "{\"from\": \"AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj\", \"to\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"amount\", \"1aergo\"}" +aergocli signtx --keystore . --password bmttest --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --jsontx "{\"Account\": \"AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R\", \"Recipient\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"Amount\": \"1aergo\", \"Type\":4, \"Nonce\":0, \"GasLimit\":0, \"chainIdHash\": \"BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn\"}" + +{"from": "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R", "to": "AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y", "amount": "1aergo"} +"{\"Account\": \"AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R\", \"Recipient\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"Amount\": \"1aergo\", \"Type\":4, \"Nonce\":1, \"GasLimit\":0, \"chainIdHash\": \"BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn\"}" diff --git a/cmd/aergosvr/aergosvr.go b/cmd/aergosvr/aergosvr.go index 9cfb7e70f..194f5185a 100644 --- a/cmd/aergosvr/aergosvr.go +++ b/cmd/aergosvr/aergosvr.go @@ -124,7 +124,7 @@ func rootRun(cmd *cobra.Command, args []string) { syncSvc := syncer.NewSyncer(cfg, chainSvc, nil) p2pSvc := p2p.NewP2P(cfg, chainSvc) pmapSvc := polarisclient.NewPolarisConnectSvc(cfg.P2P, p2pSvc) - web3.NewWeb3(rpcSvc.GetActualServer()) + web3.NewWeb3(cfg, rpcSvc.GetActualServer()) var accountSvc component.IComponent if cfg.Personal { diff --git a/config/types.go b/config/types.go index e0a2eb17f..87d730e55 100644 --- a/config/types.go +++ b/config/types.go @@ -15,6 +15,7 @@ const ( type Config struct { BaseConfig `mapstructure:",squash"` RPC *RPCConfig `mapstructure:"rpc"` + Web3 *Web3Config `mapstructure:"web3"` P2P *P2PConfig `mapstructure:"p2p"` Polaris *PolarisConfig `mapstructure:"polaris"` Blockchain *BlockchainConfig `mapstructure:"blockchain"` @@ -56,6 +57,11 @@ type RPCConfig struct { NSAllowCORS bool `mapstructure:"nsallowcors" description:"Allow CORS to RPC or REST API"` } +// Web3Config defines configurations for web3 service +type Web3Config struct { + NetServicePort int `mapstructure:"netserviceport" description:"Web3 service port"` +} + // P2PConfig defines configurations for p2p service type P2PConfig struct { // N2N (peer-to-peer) network @@ -223,6 +229,9 @@ npaddpolarises = [{{range .P2P.NPAddPolarises}} ] peerrole = "{{.P2P.PeerRole}}" +[web3] +netserviceport = {{.Web3.NetServicePort}} + [polaris] allowprivate = {{.Polaris.AllowPrivate}} genesisfile = "{{.Polaris.GenesisFile}}" diff --git a/message/blockchainmsg.go b/message/blockchainmsg.go index 0d6826d28..14696ca98 100644 --- a/message/blockchainmsg.go +++ b/message/blockchainmsg.go @@ -80,6 +80,19 @@ type GetReceiptRsp struct { Err error } +type GetReceipts struct { + BlockHash []byte +} +type GetReceiptsRsp struct { + Receipts *types.Receipts + Err error +} + +type GetReceiptsByNo struct { + BlockNo types.BlockNo +} +type GetReceiptsByNoRsp GetReceiptsRsp + type GetABI struct { Contract []byte } diff --git a/rpc/grpcserver.go b/rpc/grpcserver.go index 3207df40f..405f7e56e 100644 --- a/rpc/grpcserver.go +++ b/rpc/grpcserver.go @@ -666,6 +666,7 @@ func (rpc *AergoRPCService) CommitTX(ctx context.Context, in *types.TxList) (*ty if in.Txs == nil { return nil, status.Errorf(codes.InvalidArgument, "input tx is empty") } + rpc.hub.Get(message.MemPoolSvc) p := newPutter(ctx, in.Txs, rpc.hub, defaultActorTimeout<<2) err := p.Commit() @@ -1064,6 +1065,52 @@ func (rpc *AergoRPCService) GetReceipt(ctx context.Context, in *types.SingleByte return rsp.Receipt, rsp.Err } +func (rpc *AergoRPCService) GetReceipts(ctx context.Context, in *types.SingleBytes) (*types.Receipts, error) { + if err := rpc.checkAuth(ctx, ReadBlockChain); err != nil { + return nil, err + } + + var result interface{} + var err error + if cap(in.Value) == 0 { + return nil, status.Errorf(codes.InvalidArgument, "Received no bytes") + } + + if len(in.Value) == 32 { + result, err = rpc.hub.RequestFuture(message.ChainSvc, &message.GetReceipts{BlockHash: in.Value}, + defaultActorTimeout, "rpc.(*AergoRPCService).GetReceipts#2").Result() + } else if len(in.Value) == 8 { + number := uint64(binary.LittleEndian.Uint64(in.Value)) + result, err = rpc.hub.RequestFuture(message.ChainSvc, &message.GetReceiptsByNo{BlockNo: number}, + defaultActorTimeout, "rpc.(*AergoRPCService).GetReceipts#1").Result() + } else { + return nil, status.Errorf(codes.InvalidArgument, "Invalid input. Should be a 32 byte hash or up to 8 byte number.") + } + + if err != nil { + return nil, err + } + + + switch result.(type) { + case message.GetReceiptsRsp: + rsp, ok := result.(message.GetReceiptsRsp) + if !ok { + return nil, status.Errorf(codes.Internal, "internal type (%v) error", reflect.TypeOf(result)) + } + return rsp.Receipts, rsp.Err + + case message.GetReceiptsByNoRsp: + rsp, ok := result.(message.GetReceiptsByNoRsp) + if !ok { + return nil, status.Errorf(codes.Internal, "internal type (%v) error", reflect.TypeOf(result)) + } + return rsp.Receipts, rsp.Err + } + + return nil, status.Errorf(codes.Internal, "unexpected result type %s, expected %s", reflect.TypeOf(result), "message.GetReceipts") +} + func (rpc *AergoRPCService) GetABI(ctx context.Context, in *types.SingleBytes) (*types.ABI, error) { if err := rpc.checkAuth(ctx, ReadBlockChain); err != nil { return nil, err diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index 0accb5dd2..a5265c949 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -55,19 +55,18 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok case "/listBlockHeaders": return api.ListBlockHeaders(); case "/getBlockMetadata": return api.GetBlockMetadata(); - case "/getTransaction": return api.GetTX(); - case "/getTransactionReceipt": return api.GetReceipt(); - case "/getBlockTX": return api.GetBlockTX(); - case "/verifyTX": return api.VerifyTX(); // test - case "/call": return api.QueryContract(); // test - case "/getPastEvents": return api.ListEvents(); - case "/getABI": return api.GetABI(); - case "/queryContractState": return api.QueryContractState(); - + case "/getTransaction": return api.GetTX(); + case "/getTransactionReceipt": return api.GetReceipt(); + case "/getBlockTransactionReceipts": return api.GetReceipts(); + case "/getBlockTX": return api.GetBlockTX(); + case "/verifyTX": return api.VerifyTX(); // test + case "/call": return api.QueryContract(); + case "/getPastEvents": return api.ListEvents(); + case "/getABI": return api.GetABI(); + case "/queryContractState": return api.QueryContractState(); case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); // case "/getTransactionCount": return api.GetTransactionCount(); - // case "/getBlockTransactionReceipts": return api.GetBlockTransactionReceipts(); - + case "/getChainInfo": return api.GetChainInfo(); case "/getConsensusInfo": return api.GetConsensusInfo(); case "/getAccountVotes": return api.GetAccountVotes(); @@ -79,12 +78,8 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok case "/metric": return api.Metric(); case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); case "/getConfChangeProgress": return api.GetConfChangeProgress(); - - - - case "/chainStat": return api.ChainStat(); - case "/ListBlockMetadata": return api.ListBlockMetadata(); + // case "/ListBlockMetadata": return api.ListBlockMetadata(); default: return nil, false } @@ -99,7 +94,26 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { request := &types.Empty{} - return commonResponseHandler(api.rpc.GetAccounts(api.request.Context(), request)), true + + msg, err := api.rpc.GetAccounts(api.request.Context(), request) + + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + out := fmt.Sprintf("%s", "[") + if msg != nil { + addresslist := msg.GetAccounts() + for _, a := range addresslist { + out = fmt.Sprintf("%s\"%s\", ", out, types.EncodeAddress(a.Address)) + } + if addresslist != nil && len(out) >= 2 { + out = out[:len(out)-2] + } + } + out = fmt.Sprintf("%s%s", out, "]") + + return stringResponseHandler(out, nil), true } func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { @@ -261,7 +275,6 @@ func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { } request.Value = hashBytes } - number := values.Get("number") if number != "" { @@ -280,7 +293,12 @@ func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetBlock(api.request.Context(), request)), true + result, err := api.rpc.GetBlock(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) { @@ -351,13 +369,15 @@ func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { chainInfo = nil } - return commonResponseHandler(&types.BlockchainStatus{ + result := &types.BlockchainStatus{ BestBlockHash: last.BlockHash(), BestHeight: last.GetHeader().GetBlockNo(), ConsensusInfo: ca.GetConsensusInfo(), BestChainIdHash: bestChainIDHash, ChainInfo: chainInfo, - }, nil), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { @@ -415,7 +435,12 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetBlockBody(api.request.Context(), request)), true + result, err := api.rpc.GetBlockBody(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { @@ -467,7 +492,12 @@ func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.ListBlockHeaders(api.request.Context(), request)), true + result, err := api.rpc.ListBlockHeaders(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { @@ -504,8 +534,13 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - - return commonResponseHandler(api.rpc.GetBlockMetadata(api.request.Context(), request)), true + + result, err := api.rpc.GetBlockMetadata(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) ListBlockMetadata() (handler http.Handler, ok bool) { @@ -596,6 +631,40 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.GetReceipt(api.request.Context(), request)), true } +func (api *Web3APIv1) GetReceipts() (handler http.Handler, ok bool) { + values, err := url.ParseQuery(api.request.URL.RawQuery) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + request := &types.SingleBytes{} + hash := values.Get("hash") + if hash != "" { + hashBytes, err := base58.Decode(hash) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + request.Value = hashBytes + } + + number := values.Get("number") + if number != "" { + numberValue, err := strconv.ParseUint(number, 10, 64) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + number := uint64(numberValue) // Replace with your actual value + byteValue := make([]byte, 8) + binary.LittleEndian.PutUint64(byteValue, number) + request.Value = byteValue + } + + if _, err := govalidator.ValidateStruct(request); err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + return commonResponseHandler(api.rpc.GetReceipts(api.request.Context(), request)), true +} + func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { @@ -772,7 +841,7 @@ func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + request := &types.Query{} address := values.Get("address") if address != "" { @@ -788,24 +857,29 @@ func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { if name != "" { ci.Name = name } - + query := values.Get("query") - if query != "" { - json.Unmarshal([]byte(query), &ci.Args) + + if query != "" { + err = json.Unmarshal([]byte(query), &ci.Args) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } } callinfo, err := json.Marshal(ci) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } + request.Queryinfo = callinfo; - if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.QueryContract(api.request.Context(), request)), true + msg, err := api.rpc.QueryContract(api.request.Context(), request) + return stringResponseHandler("{\"result\":" + string(msg.Value) + "}", nil), true } func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { @@ -971,7 +1045,12 @@ func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.QueryContractState(api.request.Context(), request)), true + result, err := api.rpc.QueryContractState(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { @@ -1036,7 +1115,12 @@ func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetPeers(api.request.Context(), request)), true + result, err := api.rpc.GetPeers(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { @@ -1055,7 +1139,12 @@ func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.GetServerInfo(api.request.Context(), request)), true + result, err := api.rpc.GetServerInfo(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { @@ -1140,7 +1229,12 @@ func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(api.rpc.Metric(api.request.Context(), request)), true + result, err := api.rpc.Metric(api.request.Context(), request) + if err != nil { + return commonResponseHandler(&types.Empty{}, err), true + } + + return stringResponseHandler(util.JSON(result), nil), true } func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { @@ -1218,18 +1312,48 @@ func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - // Params - request := &types.TxBody{} - if err := json.Unmarshal(body, request); err != nil { - return commonResponseHandler(&types.Empty{}, err), true + type TxBody struct { + Nonce int64 `json:"Nonce"` + Account string `json:"Account"` + Recipient string `json:"Recipient"` + Amount string `json:"Amount"` + Type int32 `json:"Type"` + ChainIdHash string `json:"ChainIdHash"` + Sign string `json:"Sign"` } - if _, err := govalidator.ValidateStruct(request); err != nil { + type Tx struct { + Hash []byte `json:"Hash"` + Body TxBody `json:"Body"` + } + + var tx1 Tx + + if err := json.Unmarshal(body, &tx1); err != nil { return commonResponseHandler(&types.Empty{}, err), true } + + Account, err := types.DecodeAddress(tx1.Body.Account) + Recipient, err := types.DecodeAddress(tx1.Body.Recipient) + ChainIdHash, _ := base58.Decode(tx1.Body.ChainIdHash) + amountBigInt, _ := util.ParseUnit(tx1.Body.Amount) + Sign, _ := base58.Decode(tx1.Body.Sign) + + tx := &types.Tx{Hash: tx1.Hash, Body: + &types.TxBody{ + Nonce: uint64(tx1.Body.Nonce), + Account: Account, + Recipient: Recipient, + Amount: amountBigInt.Bytes(), + Type: types.TxType(tx1.Body.Type), + GasLimit:0, + ChainIdHash: ChainIdHash, + Sign: Sign, + }, + } - tx := &types.Tx{Body: request} txs := []*types.Tx{tx} + return commonResponseHandler(api.rpc.CommitTX(api.request.Context(), &types.TxList{Txs: txs})), true } diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index 6c5792dfa..b4df13abe 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -5,9 +5,13 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "github.com/aergoio/aergo-lib/log" "github.com/aergoio/aergo/rpc" + + // "golang.org/x/tools/go/cfg" + "github.com/aergoio/aergo/config" ) type RestAPI struct { @@ -23,7 +27,7 @@ var ( logger = log.NewLogger("web3") ) -func NewWeb3(rpc *rpc.AergoRPCService) { +func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { // swagger setting http.HandleFunc("/swagger.yaml", serveSwaggerYAML) http.HandleFunc("/swagger", serveSwaggerUI) @@ -32,9 +36,9 @@ func NewWeb3(rpc *rpc.AergoRPCService) { web3svcV1 := &Web3APIv1{rpc: rpc} http.HandleFunc("/v1/", web3svcV1.handler) - go func() { - fmt.Println("Web3 Server is listening on port 80...") - http.ListenAndServe(":80", nil) + go func() { + fmt.Println("Web3 Server is listening on port "+ strconv.Itoa(cfg.Web3.NetServicePort)+"...") + http.ListenAndServe(":"+strconv.Itoa(cfg.Web3.NetServicePort), nil) }() } @@ -73,6 +77,7 @@ func commonResponseHandler(response interface{}, err error) http.Handler { return } + w.Header().Set("Content-Type", "application/json") w.Write(jsonResponse) }) diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index 118cf3826..41b230b6e 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -24,7 +24,7 @@ paths: description: Successful response content: application/json: - example: {} + example: ["AmNMcKNFfpAXn2iEV2stHsZtp4W7QPb2hEvZMTgWSdafdtrW2AC3"] /getState: get: summary: 현재 잔액 및 Nonce 포함한 계정 상태 조회 @@ -350,6 +350,46 @@ paths: "feeDelegation": false, "events": [], } + /getBlockTransactionReceipts: + get: + summary: 블록에 포함된 트랜잭션 영수증(Receipt)들을 조회 + tags: [Transaction] + parameters: + - name: hash + in: query + schema: + type: string + - name: number + in: query + schema: + type: integer + responses: + "200": + description: Successful response + content: + application/json: + example: + { + "Receipts": + [ + { + "BlockNo": 0, + "BlockHash": "", + "contractAddress": "AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y", + "status": "SUCCESS", + "ret": {}, + "txHash": "C5r1VqkYWnBAHtEqJBHUjXPzbKG9f7QYXNEd5sD2KdQb", + "txIndex": 0, + "from": "", + "to": "", + "feeUsed": 0, + "gasUsed": 0, + "feeDelegation": false, + "events": [], + }, + ], + "BlockNo": 9, + } /getBlockTX: get: summary: 트랜잭션 해시로 조회한 블록 내의 트랜잭션에 대한 정보 조회 @@ -569,7 +609,22 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "events": + [ + { + "contractAddress": "AmggBF4etmnuX2rHAtKszY2GJyLXrhN3Md7tL2Y3s8JKd99xLsak", + "eventName": "save", + "Args": ["name", "hong"], + "txHash": "6bJ7RBRAE6wFPRRQVH2TUGzQt93mHEZjSVbsPYnGxpve", + "EventIdx": 0, + "BlockHash": "AahyLGkriDwqCGR4xBfgxUPo95r4ySqbiVDXUq5HJETS", + "BlockNo": 9981, + "TxIndex": 0, + }, + ], + } /getABI: get: summary: ABI 조회 @@ -584,10 +639,27 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "version": "0.2", + "language": "lua", + "functions": + [ + { + "name": "get_value", + "arguments": [{ "name": "key" }], + "view": true, + }, + { + "name": "set_value", + "arguments": [{ "name": "key" }, { "name": "value" }], + }, + ], + "state_variables": [{ "name": "values", "type": "map" }], + } /queryContractState: get: - summary: 스마트컨트랙트 상태 조회 (현재 저장값 조회용) + summary: 스마트컨트랙트 상태 조회 tags: [Transaction] parameters: - name: address @@ -658,25 +730,6 @@ paths: # application/json: # example: # transactionCount: 20 - # /getBlockTransactionReceipts: - # get: - # summary: 블록에 포함된 트랜잭션 영수증(Receipt)들을 조회 - # tags: [Transaction] - # parameters: - # - name: hash - # in: query - # schema: - # type: string - # - name: number - # in: query - # schema: - # type: integer - # responses: - # "200": - # description: Successful response - # content: - # application/json: - # example: {} /getChainInfo: get: summary: 블록체인의 현재 상태 조회 @@ -709,9 +762,9 @@ paths: type: "raft" info: '{"Leader":"local1","Total":3,"Name":"local1","RaftId":"6d3862958785a554","Status":{"id":"6d3862958785a554","term":7,"vote":"6d3862958785a554","commit":6,"lead":"6d3862958785a554","raftState":"StateLeader","applied":6,"progress":{"57779d37986cc00":{"match":6,"next":7,"state":"ProgressStateReplicate"},"cf615af53daf2c6b":{"match":6,"next":7,"state":"ProgressStateReplicate"},"6d3862958785a554":{"match":6,"next":7,"state":"ProgressStateProbe"}},"leadtransferee":"0"}}' bps: - - '{"Name":"local3","RaftID":"cf615af53daf2c6b","PeerID":"16Uiu2HAkyDXhsCj63R3ufsrYaK72nFT1RLVg5upabi6WAQtJzGoM","Addr":"/ip4/192.168.3.87/tcp/37846"}' - - '{"Name":"local1","RaftID":"6d3862958785a554","PeerID":"16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac","Addr":"/ip4/192.168.3.87/tcp/7846"}' - - '{"Name":"local2","RaftID":"57779d37986cc00","PeerID":"16Uiu2HAm82vRXcL187jRhFW9jnNjueMc7bSJLdcydNWUwxeUCC2U","Addr":"/ip4/192.168.3.87/tcp/27846"}' + - '{"Name":"local3","RaftID":"cf615af53daf2c6b","PeerID":"16Uiu2HAkyDXhsCj63R3ufsrYaK72nFT1RLVg5upabi6WAQtJzGoM","Addr":"/ip4/192.168.0.21/tcp/37846"}' + - '{"Name":"local1","RaftID":"6d3862958785a554","PeerID":"16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac","Addr":"/ip4/192.168.0.21/tcp/7846"}' + - '{"Name":"local2","RaftID":"57779d37986cc00","PeerID":"16Uiu2HAm82vRXcL187jRhFW9jnNjueMc7bSJLdcydNWUwxeUCC2U","Addr":"/ip4/192.168.0.21/tcp/27846"}' /getAccountVotes: get: summary: 가장 많이 투표된 블록 생산자 또는 시스템 변수 조회 @@ -879,7 +932,7 @@ paths: { "config": { - "NetProtocolAddr": "192.168.3.87", + "NetProtocolAddr": "192.168.0.21", "NetProtocolPort": 7846, "NPBindAddr": "0.0.0.0", "NPBindPort": 7846, @@ -914,7 +967,7 @@ paths: [ "16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac", ], - "Addresses": ["/ip4/192.168.3.87/tcp/7846"], + "Addresses": ["/ip4/192.168.0.21/tcp/7846"], "Version": "v2.4.4-134-gaa1d7d30", "Hidden": true, }, @@ -960,12 +1013,12 @@ paths: { "address": { - "address": "192.168.3.87", + "address": "192.168.0.21", "port": 37846, "peerID": "ACUIAhIhAjhSa/+nVg43tNhkJnaVx+xPjarZhVzd2PITk7uuJ8C0", "role": "Producer", "version": "v2.4.1", - "addresses": ["/ip4/192.168.3.87/tcp/37846"], + "addresses": ["/ip4/192.168.0.21/tcp/37846"], "producerIDs": [ "ACUIAhIhAjhSa/+nVg43tNhkJnaVx+xPjarZhVzd2PITk7uuJ8C0", @@ -985,12 +1038,12 @@ paths: { "address": { - "address": "192.168.3.87", + "address": "192.168.0.21", "port": 27846, "peerID": "ACUIAhIhArtT5yoZccZO1OKI5stQRZf+h6dMC+KSg2UvdS1YY0Ep", "role": "Producer", "version": "v2.4.1", - "addresses": ["/ip4/192.168.3.87/tcp/27846"], + "addresses": ["/ip4/192.168.0.21/tcp/27846"], "producerIDs": [ "ACUIAhIhArtT5yoZccZO1OKI5stQRZf+h6dMC+KSg2UvdS1YY0Ep", @@ -1029,7 +1082,7 @@ paths: { "status": { - "addr": "192.168.3.87", + "addr": "192.168.0.21", "id": "16Uiu2HAmKZUxcDNLo6BbhugZ8XfgdC4utmJ5M6HTjvFmYZ2tqTac", "port": "7846", "version": "v2.4.4-134-gaa1d7d30", diff --git a/types/receipt.go b/types/receipt.go index cf50d5398..006f04192 100644 --- a/types/receipt.go +++ b/types/receipt.go @@ -473,8 +473,8 @@ func (rm *ReceiptMerkle) GetHash() []byte { type Receipts struct { bloom *bloomFilter - receipts []*Receipt - blockNo BlockNo + Receipts []*Receipt + BlockNo BlockNo hardForkConfig BlockVersionner } @@ -482,16 +482,16 @@ func (rs *Receipts) Get() []*Receipt { if rs == nil { return nil } - return rs.receipts + return rs.Receipts } func (rs *Receipts) Set(receipts []*Receipt) { - rs.receipts = receipts + rs.Receipts = receipts } func (rs *Receipts) SetHardFork(hardForkConfig BlockVersionner, blockNo BlockNo) { rs.hardForkConfig = hardForkConfig - rs.blockNo = blockNo + rs.BlockNo = blockNo } const BloomBitByte = 256 @@ -521,13 +521,13 @@ func (rs *Receipts) MerkleRoot() []byte { if rs == nil { return merkle.CalculateMerkleRoot(nil) } - rsSize := len(rs.receipts) + rsSize := len(rs.Receipts) if rs.bloom != nil { rsSize++ } mes := make([]merkle.MerkleEntry, rsSize) - for i, r := range rs.receipts { - mes[i] = &ReceiptMerkle{r, rs.blockNo, rs.hardForkConfig} + for i, r := range rs.Receipts { + mes[i] = &ReceiptMerkle{r, rs.BlockNo, rs.hardForkConfig} } if rs.bloom != nil { mes[rsSize-1] = rs.bloom @@ -549,12 +549,12 @@ func (rs *Receipts) MarshalBinary() ([]byte, error) { } else { b.WriteByte(0) } - binary.LittleEndian.PutUint32(l, uint32(len(rs.receipts))) + binary.LittleEndian.PutUint32(l, uint32(len(rs.Receipts))) b.Write(l) var rB []byte var err error - for _, r := range rs.receipts { - if rs.hardForkConfig.IsV2Fork(rs.blockNo) { + for _, r := range rs.Receipts { + if rs.hardForkConfig.IsV2Fork(rs.BlockNo) { rB, err = r.marshalStoreBinaryV2() } else { rB, err = r.marshalStoreBinary() @@ -591,12 +591,12 @@ func (rs *Receipts) UnmarshalBinary(data []byte) error { } rCount := binary.LittleEndian.Uint32(data[pos:]) pos += 4 - rs.receipts = make([]*Receipt, rCount) + rs.Receipts = make([]*Receipt, rCount) unread := data[pos:] var err error for i := uint32(0); i < rCount; i++ { var r Receipt - if rs.hardForkConfig.IsV2Fork(rs.blockNo) { + if rs.hardForkConfig.IsV2Fork(rs.BlockNo) { unread, err = r.unmarshalStoreBinaryV2(unread) } else { unread, err = r.unmarshalStoreBinary(unread) @@ -604,7 +604,7 @@ func (rs *Receipts) UnmarshalBinary(data []byte) error { if err != nil { return err } - rs.receipts[i] = &r + rs.Receipts[i] = &r } return nil } diff --git a/types/rpc.pb.go b/types/rpc.pb.go index aa6c788a0..f304a8be6 100644 --- a/types/rpc.pb.go +++ b/types/rpc.pb.go @@ -2328,6 +2328,8 @@ type AergoRPCServiceClient interface { GetBlockTX(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*TxInBlock, error) // Return transaction receipt, queried by transaction hash GetReceipt(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*Receipt, error) + // Return transaction receipts, queried by block hash + GetReceipts(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*Receipts, error) // Return ABI stored at contract address GetABI(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*ABI, error) // Sign and send a transaction from an unlocked account @@ -2573,6 +2575,15 @@ func (c *aergoRPCServiceClient) GetReceipt(ctx context.Context, in *SingleBytes, return out, nil } +func (c *aergoRPCServiceClient) GetReceipts(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*Receipts, error) { + out := new(Receipts) + err := grpc.Invoke(ctx, "/types.AergoRPCService/GetReceipts", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *aergoRPCServiceClient) GetABI(ctx context.Context, in *SingleBytes, opts ...grpc.CallOption) (*ABI, error) { out := new(ABI) err := grpc.Invoke(ctx, "/types.AergoRPCService/GetABI", in, out, c.cc, opts...) @@ -2872,6 +2883,8 @@ type AergoRPCServiceServer interface { GetBlockTX(context.Context, *SingleBytes) (*TxInBlock, error) // Return transaction receipt, queried by transaction hash GetReceipt(context.Context, *SingleBytes) (*Receipt, error) + // Return transaction receipt, queried by block hash + GetReceipts(context.Context, *SingleBytes) (*Receipts, error) // Return ABI stored at contract address GetABI(context.Context, *SingleBytes) (*ABI, error) // Sign and send a transaction from an unlocked account @@ -3208,6 +3221,24 @@ func _AergoRPCService_GetReceipt_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _AergoRPCService_GetReceipts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SingleBytes) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AergoRPCServiceServer).GetReceipts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/types.AergoRPCService/GetReceipts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AergoRPCServiceServer).GetReceipts(ctx, req.(*SingleBytes)) + } + return interceptor(ctx, in, info, handler) +} + func _AergoRPCService_GetABI_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SingleBytes) if err := dec(in); err != nil { @@ -3753,6 +3784,10 @@ var _AergoRPCService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetReceipt", Handler: _AergoRPCService_GetReceipt_Handler, }, + { + MethodName: "GetReceipts", + Handler: _AergoRPCService_GetReceipts_Handler, + }, { MethodName: "GetABI", Handler: _AergoRPCService_GetABI_Handler, From 39e970edb3a91b8f5d139f6d80d373e2e9433589 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Tue, 26 Sep 2023 14:31:22 +0900 Subject: [PATCH 005/134] API call limit --- config/types.go | 2 + go.mod | 2 + go.sum | 4 + rpc/web3/v1.go | 213 +++++++----------------------------------- rpc/web3/web3.go | 27 ++++-- rpc/web3/web3_test.go | 34 +++++++ swagger/swagger.yaml | 92 ++---------------- 7 files changed, 102 insertions(+), 272 deletions(-) create mode 100644 rpc/web3/web3_test.go diff --git a/config/types.go b/config/types.go index 87d730e55..5b7ac2e2f 100644 --- a/config/types.go +++ b/config/types.go @@ -60,6 +60,7 @@ type RPCConfig struct { // Web3Config defines configurations for web3 service type Web3Config struct { NetServicePort int `mapstructure:"netserviceport" description:"Web3 service port"` + MaxLimit int `mapstructure:"maxlimit" description:"Web3 connect linit per second"` } // P2PConfig defines configurations for p2p service @@ -231,6 +232,7 @@ peerrole = "{{.P2P.PeerRole}}" [web3] netserviceport = {{.Web3.NetServicePort}} +maxlimit = {{.Web3.MaxLimit}} [polaris] allowprivate = {{.Polaris.AllowPrivate}} diff --git a/go.mod b/go.mod index 402e3d2af..fe4c0d748 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/dgraph-io/badger/v3 v3.2103.2 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/didip/tollbooth v4.0.2+incompatible // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/funkygao/assert v0.0.0-20160929004900-4a267e33bc79 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -120,6 +121,7 @@ require ( github.com/multiformats/go-multihash v0.0.8 // indirect github.com/multiformats/go-multistream v0.1.0 // indirect github.com/orcaman/concurrent-map v0.0.0-20190314100340-2693aad1ed75 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.2.1-0.20180930205832-81a861c69d25 // indirect github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index c36ed46e4..ec778dfef 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,8 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M= +github.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= @@ -382,6 +384,8 @@ github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/orcaman/concurrent-map v0.0.0-20190314100340-2693aad1ed75 h1:IV56VwUb9Ludyr7s53CMuEh4DdTnnQtEPLEgLyJ0kHI= github.com/orcaman/concurrent-map v0.0.0-20190314100340-2693aad1ed75/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.1-0.20180930205832-81a861c69d25 h1:a49/z+9Z5t53bD9NMajAJMe5tN0Kcz5Y6bvFxD/TPwo= github.com/pelletier/go-toml v1.2.1-0.20180930205832-81a861c69d25/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index a5265c949..4570b20dd 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -27,12 +27,10 @@ type Web3APIv1 struct { } func (api *Web3APIv1) handler(w http.ResponseWriter, r *http.Request) { - api.request = r; - + api.request = r; handler, ok := api.restAPIHandler(r) if(ok) { handler.ServeHTTP(w, r) - } else { http.NotFound(w, r) } @@ -44,48 +42,42 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok if r.Method == http.MethodGet { switch path { - case "/getAccounts": return api.GetAccounts(); - case "/getState": return api.GetState(); - case "/getProof": return api.GetStateAndProof(); - case "/getNameInfo": return api.GetNameInfo(); - case "/getBalance": return api.GetBalance(); - case "/getBlock": return api.GetBlock(); - case "/getBlockNumber": return api.Blockchain(); - case "/getBlockBody": return api.GetBlockBody(); - case "/listBlockHeaders": return api.ListBlockHeaders(); - case "/getBlockMetadata": return api.GetBlockMetadata(); - + case "/getAccounts": return api.GetAccounts(); + case "/getState": return api.GetState(); + case "/getProof": return api.GetStateAndProof(); + case "/getNameInfo": return api.GetNameInfo(); + case "/getBalance": return api.GetBalance(); + case "/getBlock": return api.GetBlock(); + case "/getBlockNumber": return api.Blockchain(); + case "/getBlockBody": return api.GetBlockBody(); + case "/listBlockHeaders": return api.ListBlockHeaders(); + case "/getBlockMetadata": return api.GetBlockMetadata(); case "/getTransaction": return api.GetTX(); case "/getTransactionReceipt": return api.GetReceipt(); case "/getBlockTransactionReceipts": return api.GetReceipts(); case "/getBlockTX": return api.GetBlockTX(); - case "/verifyTX": return api.VerifyTX(); // test case "/call": return api.QueryContract(); case "/getPastEvents": return api.ListEvents(); case "/getABI": return api.GetABI(); case "/queryContractState": return api.QueryContractState(); - case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); - // case "/getTransactionCount": return api.GetTransactionCount(); - - case "/getChainInfo": return api.GetChainInfo(); - case "/getConsensusInfo": return api.GetConsensusInfo(); - case "/getAccountVotes": return api.GetAccountVotes(); - case "/getNodeInfo": return api.NodeState(); - case "/getChainId": return api.GetPeers(); - case "/getServerInfo": return api.GetServerInfo(); - case "/getStaking": return api.GetStaking(); - case "/getVotes": return api.GetVotes(); - case "/metric": return api.Metric(); - case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); - case "/getConfChangeProgress": return api.GetConfChangeProgress(); - case "/chainStat": return api.ChainStat(); - // case "/ListBlockMetadata": return api.ListBlockMetadata(); - - default: return nil, false + case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); + case "/getChainInfo": return api.GetChainInfo(); + case "/getConsensusInfo": return api.GetConsensusInfo(); + case "/getAccountVotes": return api.GetAccountVotes(); + case "/getNodeInfo": return api.NodeState(); + case "/getChainId": return api.GetPeers(); + case "/getServerInfo": return api.GetServerInfo(); + case "/getStaking": return api.GetStaking(); + case "/getVotes": return api.GetVotes(); + case "/metric": return api.Metric(); + case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); + case "/getConfChangeProgress": return api.GetConfChangeProgress(); + case "/chainStat": return api.ChainStat(); + default: return nil, false } } else if r.Method == http.MethodPost { switch path { - case "/sendSignedTransaction": return api.CommitTX(); // test + case "/sendSignedTransaction": return api.CommitTX(); default: return nil, false } } @@ -732,110 +724,6 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { } } -func (api *Web3APIv1) VerifyTX() (handler http.Handler, ok bool) { - values, err := url.ParseQuery(api.request.URL.RawQuery) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - - // Params - request := &types.Tx{} - request.Body = &types.TxBody{} - hash := values.Get("hash") - if hash != "" { - hashBytes, err := base64.StdEncoding.DecodeString(hash) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - request.Hash = hashBytes - } - - nonce := values.Get("nonce") - if nonce != "" { - nonceValue, parseErr := strconv.ParseUint(nonce, 10, 64) - if parseErr != nil { - return commonResponseHandler(&types.Empty{}, parseErr), true - } - request.Body.Nonce = nonceValue - } - - account := values.Get("account") - if account != "" { - request.Body.Account = []byte(account) - } - - recipient := values.Get("recipient") - if recipient != "" { - recipientBytes, err := base64.StdEncoding.DecodeString(recipient) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - request.Body.Recipient = recipientBytes - } - - amount := values.Get("amount") - if amount != "" { - request.Body.Amount = []byte(amount) - } - - payload := values.Get("payload") - if payload != "" { - request.Body.Payload = []byte(payload) - } - - gasLimit := values.Get("gasLimit") - if gasLimit != "" { - gasLimitValue, parseErr := strconv.ParseUint(gasLimit, 10, 64) - if parseErr != nil { - return commonResponseHandler(&types.Empty{}, parseErr), true - } - request.Body.GasLimit = gasLimitValue - } - - gasPrice := values.Get("gasPrice") - if gasPrice != "" { - request.Body.GasPrice = []byte(gasPrice) - } - - txType := values.Get("type") - if txType != "" { - request.Body.Type = types.TxType(types.TxType_value[txType]) - } - - chainIdHash := values.Get("chainIdHash") - if hash != "" { - chainIdHashBytes, err := base64.StdEncoding.DecodeString(chainIdHash) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - request.Body.ChainIdHash = chainIdHashBytes - } - - sign := values.Get("sign") - if sign != "" { - signBytes, err := base64.StdEncoding.DecodeString(sign) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - request.Body.Sign = signBytes - } - - if _, err := govalidator.ValidateStruct(request); err != nil { - return commonResponseHandler(&types.Empty{}, err), true - } - - msg, err := api.rpc.VerifyTX(api.request.Context(), request) - if err != nil { - return commonResponseHandler(&types.Empty{}, err), true - - } - if msg.Tx != nil { - return commonResponseHandler(util.TxConvBase58Addr(msg.Tx), nil), true - } else { - return commonResponseHandler(&types.Empty{}, nil), true - } -} - func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { @@ -1275,7 +1163,7 @@ func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { return stringResponseHandler(util.B58JSON(out), nil), true } -func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -1306,54 +1194,17 @@ func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.GetConfChangeProgress(api.request.Context(), &types.SingleBytes{Value: b})), true } -func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { +func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { body, err := ioutil.ReadAll(api.request.Body) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - - type TxBody struct { - Nonce int64 `json:"Nonce"` - Account string `json:"Account"` - Recipient string `json:"Recipient"` - Amount string `json:"Amount"` - Type int32 `json:"Type"` - ChainIdHash string `json:"ChainIdHash"` - Sign string `json:"Sign"` - } - - type Tx struct { - Hash []byte `json:"Hash"` - Body TxBody `json:"Body"` - } - - var tx1 Tx - - if err := json.Unmarshal(body, &tx1); err != nil { + + txs, err := util.ParseBase58Tx([]byte(body)) + if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - - Account, err := types.DecodeAddress(tx1.Body.Account) - Recipient, err := types.DecodeAddress(tx1.Body.Recipient) - ChainIdHash, _ := base58.Decode(tx1.Body.ChainIdHash) - amountBigInt, _ := util.ParseUnit(tx1.Body.Amount) - Sign, _ := base58.Decode(tx1.Body.Sign) - - tx := &types.Tx{Hash: tx1.Hash, Body: - &types.TxBody{ - Nonce: uint64(tx1.Body.Nonce), - Account: Account, - Recipient: Recipient, - Amount: amountBigInt.Bytes(), - Type: types.TxType(tx1.Body.Type), - GasLimit:0, - ChainIdHash: ChainIdHash, - Sign: Sign, - }, - } - - txs := []*types.Tx{tx} - + return commonResponseHandler(api.rpc.CommitTX(api.request.Context(), &types.TxList{Txs: txs})), true } diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index b4df13abe..62969daa2 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -10,8 +10,8 @@ import ( "github.com/aergoio/aergo-lib/log" "github.com/aergoio/aergo/rpc" - // "golang.org/x/tools/go/cfg" "github.com/aergoio/aergo/config" + "github.com/didip/tollbooth" ) type RestAPI struct { @@ -28,17 +28,28 @@ var ( ) func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { - // swagger setting - http.HandleFunc("/swagger.yaml", serveSwaggerYAML) - http.HandleFunc("/swagger", serveSwaggerUI) + mux := http.NewServeMux() + + // set limit per second + maxLimit := float64(1) + if cfg.Web3.MaxLimit != 0 { + maxLimit = float64(cfg.Web3.MaxLimit) + } + + limiter := tollbooth.NewLimiter(maxLimit, nil) + limiter.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}) - // v1 + // swagger + mux.HandleFunc("/swagger.yaml", serveSwaggerYAML) + mux.HandleFunc("/swagger", serveSwaggerUI) + + // API v1 web3svcV1 := &Web3APIv1{rpc: rpc} - http.HandleFunc("/v1/", web3svcV1.handler) - + mux.Handle("/v1/", tollbooth.LimitHandler(limiter, http.HandlerFunc(web3svcV1.handler))) + go func() { fmt.Println("Web3 Server is listening on port "+ strconv.Itoa(cfg.Web3.NetServicePort)+"...") - http.ListenAndServe(":"+strconv.Itoa(cfg.Web3.NetServicePort), nil) + http.ListenAndServe(":"+strconv.Itoa(cfg.Web3.NetServicePort), mux) }() } diff --git a/rpc/web3/web3_test.go b/rpc/web3/web3_test.go new file mode 100644 index 000000000..d075f824e --- /dev/null +++ b/rpc/web3/web3_test.go @@ -0,0 +1,34 @@ +package web3 + +import ( + "net/http" + "testing" + "time" +) + +func TestRateLimitMiddleware(t *testing.T) { + url := "http://localhost/v1/getBlock?number=1" + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 10; i++ { + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusTooManyRequests { + t.Logf("Request %d: Rate limit exceeded", i+1) + } else if resp.StatusCode == http.StatusOK { + t.Logf("Request %d: OK", i+1) + } else { + t.Errorf("Request %d: Unexpected status code %d", i+1, resp.StatusCode) + } + + time.Sleep(100 * time.Millisecond) + } +} \ No newline at end of file diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index 41b230b6e..d77a0e20b 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -426,72 +426,6 @@ paths: }, }, } - /verifyTX: - get: - summary: 트랜잭션의 유효성 검증 - tags: [Transaction] - parameters: - - name: hash - in: query - schema: - type: string - - name: nonce - in: query - schema: - type: integer - - name: account - in: query - schema: - type: string - - name: recipient - in: query - schema: - type: string - - name: amount - in: query - schema: - type: string - - name: payload - in: query - schema: - type: string - - name: gasLimit - in: query - schema: - type: integer - - name: gasPrice - in: query - schema: - type: string - - name: type - in: query - schema: - type: string - enum: - [ - "NORMAL", - "GOVERNANCE", - "REDEPLOY", - "FEEDELEGATION", - "TRANSFER", - "CALL", - "DEPLOY", - ] - example: "NORMAL" - - name: chainIdHash - in: query - schema: - type: string - - name: sign - in: query - schema: - type: string - responses: - "200": - description: Successful response - content: - application/json: - example: {} /sendSignedTransaction: post: summary: 서명된 트랜잭션을 커밋 @@ -540,7 +474,15 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "results": + [ + { + "hash": "pK5LKSZ1mKIJyGJSkM4T496pCTu1xQhXv8ZBdjXTkkg=", + }, + ], + } /call: get: summary: 스마트 컨트랙트의 상태 조회 @@ -714,22 +656,6 @@ paths: application/json: example: transactionCount: 10 - # /getTransactionCount: - # get: - # summary: 주소에서 발생한 트랜잭션 개수를 조회 - # tags: [Transaction] - # parameters: - # - name: address - # in: query - # schema: - # type: string - # responses: - # "200": - # description: Successful response - # content: - # application/json: - # example: - # transactionCount: 20 /getChainInfo: get: summary: 블록체인의 현재 상태 조회 From 7e7cf6bc3c04203e20aedd992e57009f10475096 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Tue, 26 Sep 2023 14:32:10 +0900 Subject: [PATCH 006/134] api call limit --- aergo-protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aergo-protobuf b/aergo-protobuf index 9cbb5167c..1d56e9d51 160000 --- a/aergo-protobuf +++ b/aergo-protobuf @@ -1 +1 @@ -Subproject commit 9cbb5167c325a9adea21364522a353a12e0be789 +Subproject commit 1d56e9d512e101ecd9aea5809c56015205f0b4ee From 7c9e6f344a550de77c08ef8f4f395c3e0a1ab178 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Tue, 26 Sep 2023 14:39:16 +0900 Subject: [PATCH 007/134] swagger call example edit --- swagger/swagger.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml index d77a0e20b..73bb384c3 100644 --- a/swagger/swagger.yaml +++ b/swagger/swagger.yaml @@ -508,7 +508,20 @@ paths: description: Successful response content: application/json: - example: {} + example: + { + "Hash": "GwnLivMvAXKqoRCwQkhvrm8biC4JhpcJgmBL84iBnPtp", + "Body": + { + "Nonce": 2, + "Account": "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R", + "Recipient": "AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y", + "Amount": "1000000000000000000", + "Type": 4, + "ChainIdHash": "BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn", + "Sign": "AN1rKvtDAYfLhSXNHCXLzi36a7ZjNbp7jhsJoM5ZdyLNZbGLgqDaDRPoNYFwUCVwpCVMqf3kLotB1jmiYMBzjmGeWN7pmsSDs", + }, + } /getPastEvents: get: summary: 지난 이벤트를 조회 From df770eff78b9ef9689ee96db0e30664165cac698 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Tue, 26 Sep 2023 14:51:29 +0900 Subject: [PATCH 008/134] Delete invalid value (signtx_test.go) --- cmd/aergocli/cmd/signtx_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmd/aergocli/cmd/signtx_test.go b/cmd/aergocli/cmd/signtx_test.go index 4c5cfc9e3..bd1d56d28 100644 --- a/cmd/aergocli/cmd/signtx_test.go +++ b/cmd/aergocli/cmd/signtx_test.go @@ -53,9 +53,3 @@ func TestSignWithPath(t *testing.T) { os.RemoveAll(testDir) } -// aergocli signtx --from AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --to AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y --amount 1aergo --password bmttest -// aergocli signtx --keystore . --password bmttest --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --jsontx "{\"from\": \"AmNdzAYv3dYKFtPRgfUMGppGwBJS2JvZLRTF9gRruF49vppEepgj\", \"to\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"amount\", \"1aergo\"}" -aergocli signtx --keystore . --password bmttest --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R --jsontx "{\"Account\": \"AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R\", \"Recipient\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"Amount\": \"1aergo\", \"Type\":4, \"Nonce\":0, \"GasLimit\":0, \"chainIdHash\": \"BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn\"}" - -{"from": "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R", "to": "AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y", "amount": "1aergo"} -"{\"Account\": \"AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R\", \"Recipient\": \"AmM1M4jAxeTxfh9CHUmKXJwTLxGJ6Qe5urEeFXqbqkKnZ73Uvx4y\", \"Amount\": \"1aergo\", \"Type\":4, \"Nonce\":1, \"GasLimit\":0, \"chainIdHash\": \"BNVSYKKqSR78hTSrxkaroFK2S3mgsoocpWg9HYtb1Zhn\"}" From a310587c0849e09b845a67a226c0451430d5dab8 Mon Sep 17 00:00:00 2001 From: jinuk-shin Date: Thu, 19 Oct 2023 11:56:41 +0900 Subject: [PATCH 009/134] Set Cors --- rpc/web3/web3.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index 62969daa2..5f8d48e37 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -12,6 +12,7 @@ import ( "github.com/aergoio/aergo/config" "github.com/didip/tollbooth" + "github.com/rs/cors" ) type RestAPI struct { @@ -43,9 +44,16 @@ func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { mux.HandleFunc("/swagger.yaml", serveSwaggerYAML) mux.HandleFunc("/swagger", serveSwaggerUI) + c := cors.New(cors.Options{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST"}, + AllowedHeaders: []string{"*"}, + AllowCredentials: true, + }) + // API v1 web3svcV1 := &Web3APIv1{rpc: rpc} - mux.Handle("/v1/", tollbooth.LimitHandler(limiter, http.HandlerFunc(web3svcV1.handler))) + mux.Handle("/v1/", tollbooth.LimitHandler(limiter, c.Handler(http.HandlerFunc(web3svcV1.handler)))) go func() { fmt.Println("Web3 Server is listening on port "+ strconv.Itoa(cfg.Web3.NetServicePort)+"...") From 8e305cc66e7674e5f64ea0c71ba292cec0f67e4c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 24 Oct 2023 14:54:01 +0000 Subject: [PATCH 010/134] use the dbkey package --- pkg/trie/trie.go | 13 +------------ pkg/trie/trie_cache.go | 2 +- pkg/trie/trie_revert.go | 4 ++-- pkg/trie/trie_test.go | 10 +++++----- pkg/trie/trie_tools.go | 4 ++-- types/dbkey/key.go | 7 +++++++ types/dbkey/schema.go | 5 +++++ 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/pkg/trie/trie.go b/pkg/trie/trie.go index 7ac295a47..122404db3 100644 --- a/pkg/trie/trie.go +++ b/pkg/trie/trie.go @@ -13,13 +13,6 @@ import ( "github.com/aergoio/aergo-lib/db" ) - -var ( - // triePrefix is the prefix for the trie keys in the db. - triePrefix = []byte{'s'} -) - - // Trie is a modified sparse Merkle tree. // Instead of storing values at the leaves of the tree, // the values are stored at the highest subtree root that contains only that value. @@ -489,7 +482,7 @@ func (s *Trie) loadBatch(root []byte) ([][]byte, error) { s.loadDbMux.Unlock() } s.db.lock.Lock() - dbval := s.db.Store.Get(trieKey(root[:HashLength])) + dbval := s.db.Store.Get(dbkey.Trie(root[:HashLength])) s.db.lock.Unlock() nodeSize := len(dbval) if nodeSize != 0 { @@ -590,7 +583,3 @@ func (s *Trie) updatePastTries() { s.pastTries = append(s.pastTries, s.Root) } } - -func trieKey(key []byte) []byte { - return append(triePrefix, key...) -} diff --git a/pkg/trie/trie_cache.go b/pkg/trie/trie_cache.go index d765006e9..65d9b997b 100644 --- a/pkg/trie/trie_cache.go +++ b/pkg/trie/trie_cache.go @@ -41,7 +41,7 @@ func (c *CacheDB) commit(txn *DbTx) { c.updatedMux.Lock() defer c.updatedMux.Unlock() for key, batch := range c.updatedNodes { - (*txn).Set(trieKey(key[:]), c.serializeBatch(batch)) + (*txn).Set(dbkey.Trie(key[:]), c.serializeBatch(batch)) } } diff --git a/pkg/trie/trie_revert.go b/pkg/trie/trie_revert.go index fdc4fe124..05d452b42 100644 --- a/pkg/trie/trie_revert.go +++ b/pkg/trie/trie_revert.go @@ -50,7 +50,7 @@ func (s *Trie) Revert(toOldRoot []byte) error { // NOTE The tx interface doesnt handle ErrTxnTooBig txn := s.db.Store.NewTx() for _, key := range s.db.nodesToRevert { - txn.Delete(trieKey(key[:HashLength])) + txn.Delete(dbkey.Trie(key[:HashLength])) } txn.Commit() @@ -62,7 +62,7 @@ func (s *Trie) Revert(toOldRoot []byte) error { // If toOldRoot is a shortcut batch, it is possible that // revert has deleted it if the key was ever stored at height0 // because in leafHash byte(0) = byte(256) - s.db.Store.Set(trieKey(toOldRoot), s.db.serializeBatch(batch)) + s.db.Store.Set(dbkey.Trie(toOldRoot), s.db.serializeBatch(batch)) } return nil } diff --git a/pkg/trie/trie_test.go b/pkg/trie/trie_test.go index 367e68d8c..f70dbdf0d 100644 --- a/pkg/trie/trie_test.go +++ b/pkg/trie/trie_test.go @@ -358,10 +358,10 @@ func TestTrieRevert(t *testing.T) { root2, _ := smt.Update([][]byte{key1}, [][]byte{values[1]}) smt.Commit() smt.Revert(root) - if len(smt.db.Store.Get(trieKey(root))) == 0 { + if len(smt.db.Store.Get(dbkey.Trie(root))) == 0 { t.Fatal("shortcut node shouldnt be deleted by revert") } - if len(smt.db.Store.Get(trieKey(root2))) != 0 { + if len(smt.db.Store.Get(dbkey.Trie(root2))) != 0 { t.Fatal("reverted root should have been deleted") } key1 = make([]byte, 32, 32) @@ -370,7 +370,7 @@ func TestTrieRevert(t *testing.T) { smt.Update([][]byte{key1}, [][]byte{values[1]}) smt.Commit() smt.Revert(root) - if len(smt.db.Store.Get(trieKey(root))) == 0 { + if len(smt.db.Store.Get(dbkey.Trie(root))) == 0 { t.Fatal("shortcut node shouldnt be deleted by revert") } @@ -412,12 +412,12 @@ func TestTrieRevert(t *testing.T) { } // Check all reverted nodes have been deleted for node := range updatedNodes2 { - if len(smt.db.Store.Get(trieKey(node[:]))) != 0 { + if len(smt.db.Store.Get(dbkey.Trie(node[:]))) != 0 { t.Fatal("nodes not deleted from database", node) } } for node := range updatedNodes1 { - if len(smt.db.Store.Get(trieKey(node[:]))) != 0 { + if len(smt.db.Store.Get(dbkey.Trie(node[:]))) != 0 { t.Fatal("nodes not deleted from database", node) } } diff --git a/pkg/trie/trie_tools.go b/pkg/trie/trie_tools.go index 63105148c..398b5e347 100644 --- a/pkg/trie/trie_tools.go +++ b/pkg/trie/trie_tools.go @@ -35,7 +35,7 @@ func (s *Trie) loadCache(root []byte, batch [][]byte, iBatch, height int, ch cha if height%4 == 0 { // Load the node from db s.db.lock.Lock() - dbval := s.db.Store.Get(trieKey(root[:HashLength])) + dbval := s.db.Store.Get(dbkey.Trie(root[:HashLength])) s.db.lock.Unlock() if len(dbval) == 0 { ch <- fmt.Errorf("the trie node %x is unavailable in the disk db, db may be corrupted", root) @@ -113,7 +113,7 @@ func (s *Trie) get(root, key []byte, batch [][]byte, iBatch, height int) ([]byte // TrieRootExists returns true if the root exists in Database. func (s *Trie) TrieRootExists(root []byte) bool { s.db.lock.RLock() - dbval := s.db.Store.Get(trieKey(root)) + dbval := s.db.Store.Get(dbkey.Trie(root)) s.db.lock.RUnlock() if len(dbval) != 0 { return true diff --git a/types/dbkey/key.go b/types/dbkey/key.go index 56b2331ea..1f4f83788 100644 --- a/types/dbkey/key.go +++ b/types/dbkey/key.go @@ -7,6 +7,13 @@ import ( "github.com/aergoio/aergo/v2/types" ) +//---------------------------------------------------------------------------------// +// state trie + +func Trie(key []byte) []byte { + return append(triePrefix, key...) +} + //---------------------------------------------------------------------------------// // chain diff --git a/types/dbkey/schema.go b/types/dbkey/schema.go index 0713bb825..311481c58 100644 --- a/types/dbkey/schema.go +++ b/types/dbkey/schema.go @@ -1,6 +1,11 @@ // package dbkey contains a key prefix collection of low level database accessors. package dbkey +// state trie +const ( + triePrefix = "s" +) + // chain const ( receiptsPrefix = "r" From d17db23a62529fab8f590f447f06d7780829605c Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Tue, 24 Oct 2023 15:10:38 +0000 Subject: [PATCH 011/134] fix build --- pkg/trie/trie.go | 1 + pkg/trie/trie_cache.go | 1 + pkg/trie/trie_revert.go | 2 ++ pkg/trie/trie_test.go | 1 + pkg/trie/trie_tools.go | 1 + types/dbkey/key.go | 2 +- 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/trie/trie.go b/pkg/trie/trie.go index 122404db3..9da9e3050 100644 --- a/pkg/trie/trie.go +++ b/pkg/trie/trie.go @@ -11,6 +11,7 @@ import ( "sync" "github.com/aergoio/aergo-lib/db" + "github.com/aergoio/aergo/v2/types/dbkey" ) // Trie is a modified sparse Merkle tree. diff --git a/pkg/trie/trie_cache.go b/pkg/trie/trie_cache.go index 65d9b997b..c95df166b 100644 --- a/pkg/trie/trie_cache.go +++ b/pkg/trie/trie_cache.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/aergoio/aergo-lib/db" + "github.com/aergoio/aergo/v2/types/dbkey" ) // DbTx represents Set and Delete interface to store data diff --git a/pkg/trie/trie_revert.go b/pkg/trie/trie_revert.go index 05d452b42..080d74d54 100644 --- a/pkg/trie/trie_revert.go +++ b/pkg/trie/trie_revert.go @@ -8,6 +8,8 @@ package trie import ( "bytes" "fmt" + + "github.com/aergoio/aergo/v2/types/dbkey" ) // Revert rewinds the state tree to a previous version diff --git a/pkg/trie/trie_test.go b/pkg/trie/trie_test.go index f70dbdf0d..8c442d3f9 100644 --- a/pkg/trie/trie_test.go +++ b/pkg/trie/trie_test.go @@ -18,6 +18,7 @@ import ( "github.com/aergoio/aergo-lib/db" "github.com/aergoio/aergo/v2/internal/common" + "github.com/aergoio/aergo/v2/types/dbkey" ) func TestTrieEmpty(t *testing.T) { diff --git a/pkg/trie/trie_tools.go b/pkg/trie/trie_tools.go index 398b5e347..29afc7009 100644 --- a/pkg/trie/trie_tools.go +++ b/pkg/trie/trie_tools.go @@ -10,6 +10,7 @@ import ( "fmt" "github.com/aergoio/aergo-lib/db" + "github.com/aergoio/aergo/v2/types/dbkey" ) // LoadCache loads the first layers of the merkle tree given a root diff --git a/types/dbkey/key.go b/types/dbkey/key.go index 1f4f83788..b25be2cdc 100644 --- a/types/dbkey/key.go +++ b/types/dbkey/key.go @@ -11,7 +11,7 @@ import ( // state trie func Trie(key []byte) []byte { - return append(triePrefix, key...) + return append([]byte(triePrefix), key...) } //---------------------------------------------------------------------------------// From 7cf26425f2940f09721f84c42b2cfc30dc447e74 Mon Sep 17 00:00:00 2001 From: gokch Date: Thu, 2 Nov 2023 07:48:59 +0000 Subject: [PATCH 012/134] fmt go code --- chain/chainhandle.go | 12 +- chain/chainservice.go | 4 +- config/types.go | 4 +- rpc/grpcserver.go | 7 +- rpc/rpc.go | 733 +++++++++++++++++++++--------------------- rpc/web3/v1.go | 327 ++++++++++--------- rpc/web3/web3.go | 22 +- rpc/web3/web3_test.go | 4 +- 8 files changed, 568 insertions(+), 545 deletions(-) diff --git a/chain/chainhandle.go b/chain/chainhandle.go index dbc76b786..38ac9a02d 100644 --- a/chain/chainhandle.go +++ b/chain/chainhandle.go @@ -160,18 +160,18 @@ func (cs *ChainService) getReceipts(blockHash []byte) (*types.Receipts, error) { } } } - - return receipts, nil + + return receipts, nil } func (cs *ChainService) getReceiptsByNo(blockNo types.BlockNo) (*types.Receipts, error) { blockInMainChain, err := cs.cdb.GetBlockByNo(blockNo) - + block, err := cs.cdb.getBlock(blockInMainChain.BlockHash()) if !bytes.Equal(block.BlockHash(), blockInMainChain.BlockHash()) { return nil, errors.New("cannot find a receipt") } - + receipts, err := cs.cdb.getReceipts(block.BlockHash(), block.GetHeader().BlockNo, cs.cfg.Hardfork) if err != nil { return nil, err @@ -190,8 +190,8 @@ func (cs *ChainService) getReceiptsByNo(blockNo types.BlockNo) (*types.Receipts, } } } - - return receipts, nil + + return receipts, nil } func (cs *ChainService) getEvents(events *[]*types.Event, blkNo types.BlockNo, filter *types.FilterInfo, diff --git a/chain/chainservice.go b/chain/chainservice.go index bb5f1f6df..e77b4b04e 100644 --- a/chain/chainservice.go +++ b/chain/chainservice.go @@ -781,13 +781,13 @@ func (cw *ChainWorker) Receive(context actor.Context) { receipts, err := cw.getReceipts(msg.BlockHash) context.Respond(message.GetReceiptsRsp{ Receipts: receipts, - Err: err, + Err: err, }) case *message.GetReceiptsByNo: receipts, err := cw.getReceiptsByNo(msg.BlockNo) context.Respond(message.GetReceiptsByNoRsp{ Receipts: receipts, - Err: err, + Err: err, }) case *message.GetABI: sdb = cw.sdb.OpenNewStateDB(cw.sdb.GetRoot()) diff --git a/config/types.go b/config/types.go index 5b7ac2e2f..91401d8f3 100644 --- a/config/types.go +++ b/config/types.go @@ -59,8 +59,8 @@ type RPCConfig struct { // Web3Config defines configurations for web3 service type Web3Config struct { - NetServicePort int `mapstructure:"netserviceport" description:"Web3 service port"` - MaxLimit int `mapstructure:"maxlimit" description:"Web3 connect linit per second"` + NetServicePort int `mapstructure:"netserviceport" description:"Web3 service port"` + MaxLimit int `mapstructure:"maxlimit" description:"Web3 connect linit per second"` } // P2PConfig defines configurations for p2p service diff --git a/rpc/grpcserver.go b/rpc/grpcserver.go index c0afd4970..0a1a47d78 100644 --- a/rpc/grpcserver.go +++ b/rpc/grpcserver.go @@ -77,7 +77,7 @@ const defaultActorTimeout = time.Second * 3 var _ types.AergoRPCServiceServer = (*AergoRPCService)(nil) func (ns *AergoRPCService) GetActorHelper() p2pcommon.ActorService { - return ns.actorHelper + return ns.actorHelper } func (rpc *AergoRPCService) SetConsensusAccessor(ca consensus.ConsensusAccessor) { @@ -668,7 +668,7 @@ func (rpc *AergoRPCService) CommitTX(ctx context.Context, in *types.TxList) (*ty if in.Txs == nil { return nil, status.Errorf(codes.InvalidArgument, "input tx is empty") } - + rpc.hub.Get(message.MemPoolSvc) p := newPutter(ctx, in.Txs, rpc.hub, defaultActorTimeout<<2) err := p.Commit() @@ -1092,8 +1092,7 @@ func (rpc *AergoRPCService) GetReceipts(ctx context.Context, in *types.SingleByt if err != nil { return nil, err } - - + switch result.(type) { case message.GetReceiptsRsp: rsp, ok := result.(message.GetReceiptsRsp) diff --git a/rpc/rpc.go b/rpc/rpc.go index 496988da0..725405293 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -39,236 +39,236 @@ import ( ) // RPC is actor for providing rpc service - type RPC struct { - conf *config.Config - - *component.BaseComponent - - grpcServer *grpc.Server - grpcWebServer *grpcweb.WrappedGrpcServer - actualServer *AergoRPCService - httpServer *http.Server - - ca types.ChainAccessor - version string - entConf *types.EnterpriseConfig - } - - //var _ component.IComponent = (*RPCComponent)(nil) - - // NewRPC create an rpc service - func NewRPC(cfg *config.Config, chainAccessor types.ChainAccessor, version string) *RPC { - actualServer := &AergoRPCService{ - msgHelper: message.GetHelper(), - blockStream: make(map[uint32]*ListBlockStream), - blockMetadataStream: make(map[uint32]*ListBlockMetaStream), - eventStream: make(map[*EventStream]*EventStream), - } - - tracer := opentracing.GlobalTracer() - - opts := make([]grpc.ServerOption, 0) - - if cfg.RPC.NetServiceTrace { - opts = append(opts, grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer))) - opts = append(opts, grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer))) - } - - var entConf *types.EnterpriseConfig - genesis := chainAccessor.GetGenesisInfo() - if !genesis.ID.PublicNet { - conf, err := chainAccessor.GetEnterpriseConfig("rpcpermissions") - if err != nil { - logger.Error().Err(err).Msg("could not get allowed client information") - } else { - entConf = conf - } - } - - if cfg.RPC.NSEnableTLS { - certificate, err := tls.LoadX509KeyPair(cfg.RPC.NSCert, cfg.RPC.NSKey) - if err != nil { - logger.Error().Err(err).Msg("could not load server key pair") - } - certPool := x509.NewCertPool() - ca, err := ioutil.ReadFile(cfg.RPC.NSCACert) - if err != nil { - logger.Error().Err(err).Msg("could not read CA cert") - } - if ok := certPool.AppendCertsFromPEM(ca); !ok { - logger.Error().Bool("AppendCertsFromPEM", ok).Msg("failed to append server cert") - err = fmt.Errorf("failed to append server cert") - } - if err == nil { - creds := credentials.NewTLS(&tls.Config{ - ClientAuth: tls.RequireAndVerifyClientCert, - Certificates: []tls.Certificate{certificate}, - ClientCAs: certPool, - }) - opts = append(opts, grpc.Creds(creds)) - logger.Info().Str("cert", cfg.RPC.NSCert).Str("key", cfg.RPC.NSKey).Msg("grpc with TLS") - } - } - - grpcServer := network.GRPCSeverBuilder(). - MessageSize(int(types.GetMaxMessageSize(cfg.Blockchain.MaxBlockSize))). - Opts(opts). - GetInstance() - - grpcWebServer := grpcweb.WrapServer( - grpcServer, - grpcweb.WithWebsockets(true), - grpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool { - return true - })) - - rpcsvc := &RPC{ - conf: cfg, - - grpcServer: grpcServer, - grpcWebServer: grpcWebServer, - actualServer: actualServer, - ca: chainAccessor, - version: version, - } - rpcsvc.BaseComponent = component.NewBaseComponent(message.RPCSvc, rpcsvc, logger) - - actualServer.actorHelper = rpcsvc - actualServer.setClientAuth(entConf) - - rpcsvc.httpServer = &http.Server{ - Handler: rpcsvc.grpcWebHandlerFunc(grpcWebServer, http.DefaultServeMux, actualServer), - ReadTimeout: 4 * time.Second, - WriteTimeout: 4 * time.Second, - MaxHeaderBytes: 1 << 20, - } - - return rpcsvc - } - - func (ns *RPC) GetActualServer() *AergoRPCService { - return ns.actualServer - } - - func (ns *RPC) SetHub(hub *component.ComponentHub) { - ns.actualServer.hub = hub - ns.BaseComponent.SetHub(hub) - } - - func (ns *RPC) SetConsensusAccessor(ca consensus.ConsensusAccessor) { - ns.actualServer.SetConsensusAccessor(ca) - } - - // Start start rpc service. - func (ns *RPC) BeforeStart() { - aergorpc.RegisterAergoRPCServiceServer(ns.grpcServer, ns.actualServer) - } - - func (ns *RPC) AfterStart() { - go ns.serve() - } - - // Stop stops rpc service. - func (ns *RPC) BeforeStop() { - ns.httpServer.Close() - ns.grpcServer.Stop() - } - - func (ns *RPC) Statistics() *map[string]interface{} { - return &map[string]interface{}{ - "config": ns.conf.RPC, - "version": ns.version, - "streams": ns.actualServer.Statistics(), - } - } - - func (ns *RPC) Receive(context actor.Context) { - switch msg := context.Message().(type) { - case *types.Block: - server := ns.actualServer - server.BroadcastToListBlockStream(msg) - meta := msg.GetMetadata() - server.BroadcastToListBlockMetadataStream(meta) - case []*types.Event: - server := ns.actualServer - for _, e := range msg { - if bytes.Equal(e.GetContractAddress(), types.AddressPadding([]byte(types.AergoEnterprise))) { - eventName := strings.Split(e.GetEventName(), " ") - conf := strings.ToUpper(eventName[1]) - switch eventName[0] { - case "Enable": - if conf == enterprise.RPCPermissions { - value := false - if e.JsonArgs == "true" { - value = true - } - server.setClientAuthOn(value) - } else if conf == enterprise.AccountWhite { - value := false - if e.JsonArgs == "true" { - value = true - } - msg := &message.MemPoolEnableWhitelist{On: value} - ns.TellTo(message.MemPoolSvc, msg) - } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { - value := false - if e.JsonArgs == "true" { - value = true - } - msg := message.P2PWhiteListConfEnableEvent{Name: conf, On: value} - ns.TellTo(message.P2PSvc, msg) - } - case "Set": - if conf == enterprise.RPCPermissions { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - server.setClientAuthMap(values) - } else if conf == enterprise.AccountWhite { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - msg := &message.MemPoolSetWhitelist{ - Accounts: values, - } - ns.TellTo(message.MemPoolSvc, msg) - } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { - values := make([]string, 1024) - if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { - return - } - msg := message.P2PWhiteListConfSetEvent{ - Values: values, - } - ns.TellTo(message.P2PSvc, msg) - } - default: - logger.Warn().Str("Enterprise event", eventName[0]).Str("conf",conf).Msg("unknown message in RPCPERMISSION") - } - } - } - server.BroadcastToEventStream(msg) - case *message.GetServerInfo: - context.Respond(ns.CollectServerInfo(msg.Categories)) - case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing - // Ignore actor lfiecycle messages - default: - ns.Warn().Msgf("unknown msg received in rpc %s", reflect.TypeOf(msg).String()) - } - } - - // Create HTTP handler that redirects matching grpc-web requests to the grpc-web wrapper. - func (ns *RPC) grpcWebHandlerFunc(grpcWebServer *grpcweb.WrappedGrpcServer, otherHandler http.Handler, actualServer *AergoRPCService) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +type RPC struct { + conf *config.Config + + *component.BaseComponent + + grpcServer *grpc.Server + grpcWebServer *grpcweb.WrappedGrpcServer + actualServer *AergoRPCService + httpServer *http.Server + + ca types.ChainAccessor + version string + entConf *types.EnterpriseConfig +} + +//var _ component.IComponent = (*RPCComponent)(nil) + +// NewRPC create an rpc service +func NewRPC(cfg *config.Config, chainAccessor types.ChainAccessor, version string) *RPC { + actualServer := &AergoRPCService{ + msgHelper: message.GetHelper(), + blockStream: make(map[uint32]*ListBlockStream), + blockMetadataStream: make(map[uint32]*ListBlockMetaStream), + eventStream: make(map[*EventStream]*EventStream), + } + + tracer := opentracing.GlobalTracer() + + opts := make([]grpc.ServerOption, 0) + + if cfg.RPC.NetServiceTrace { + opts = append(opts, grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer))) + opts = append(opts, grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer))) + } + + var entConf *types.EnterpriseConfig + genesis := chainAccessor.GetGenesisInfo() + if !genesis.ID.PublicNet { + conf, err := chainAccessor.GetEnterpriseConfig("rpcpermissions") + if err != nil { + logger.Error().Err(err).Msg("could not get allowed client information") + } else { + entConf = conf + } + } + + if cfg.RPC.NSEnableTLS { + certificate, err := tls.LoadX509KeyPair(cfg.RPC.NSCert, cfg.RPC.NSKey) + if err != nil { + logger.Error().Err(err).Msg("could not load server key pair") + } + certPool := x509.NewCertPool() + ca, err := ioutil.ReadFile(cfg.RPC.NSCACert) + if err != nil { + logger.Error().Err(err).Msg("could not read CA cert") + } + if ok := certPool.AppendCertsFromPEM(ca); !ok { + logger.Error().Bool("AppendCertsFromPEM", ok).Msg("failed to append server cert") + err = fmt.Errorf("failed to append server cert") + } + if err == nil { + creds := credentials.NewTLS(&tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + Certificates: []tls.Certificate{certificate}, + ClientCAs: certPool, + }) + opts = append(opts, grpc.Creds(creds)) + logger.Info().Str("cert", cfg.RPC.NSCert).Str("key", cfg.RPC.NSKey).Msg("grpc with TLS") + } + } + + grpcServer := network.GRPCSeverBuilder(). + MessageSize(int(types.GetMaxMessageSize(cfg.Blockchain.MaxBlockSize))). + Opts(opts). + GetInstance() + + grpcWebServer := grpcweb.WrapServer( + grpcServer, + grpcweb.WithWebsockets(true), + grpcweb.WithWebsocketOriginFunc(func(req *http.Request) bool { + return true + })) + + rpcsvc := &RPC{ + conf: cfg, + + grpcServer: grpcServer, + grpcWebServer: grpcWebServer, + actualServer: actualServer, + ca: chainAccessor, + version: version, + } + rpcsvc.BaseComponent = component.NewBaseComponent(message.RPCSvc, rpcsvc, logger) + + actualServer.actorHelper = rpcsvc + actualServer.setClientAuth(entConf) + + rpcsvc.httpServer = &http.Server{ + Handler: rpcsvc.grpcWebHandlerFunc(grpcWebServer, http.DefaultServeMux, actualServer), + ReadTimeout: 4 * time.Second, + WriteTimeout: 4 * time.Second, + MaxHeaderBytes: 1 << 20, + } + + return rpcsvc +} + +func (ns *RPC) GetActualServer() *AergoRPCService { + return ns.actualServer +} + +func (ns *RPC) SetHub(hub *component.ComponentHub) { + ns.actualServer.hub = hub + ns.BaseComponent.SetHub(hub) +} + +func (ns *RPC) SetConsensusAccessor(ca consensus.ConsensusAccessor) { + ns.actualServer.SetConsensusAccessor(ca) +} + +// Start start rpc service. +func (ns *RPC) BeforeStart() { + aergorpc.RegisterAergoRPCServiceServer(ns.grpcServer, ns.actualServer) +} + +func (ns *RPC) AfterStart() { + go ns.serve() +} + +// Stop stops rpc service. +func (ns *RPC) BeforeStop() { + ns.httpServer.Close() + ns.grpcServer.Stop() +} + +func (ns *RPC) Statistics() *map[string]interface{} { + return &map[string]interface{}{ + "config": ns.conf.RPC, + "version": ns.version, + "streams": ns.actualServer.Statistics(), + } +} + +func (ns *RPC) Receive(context actor.Context) { + switch msg := context.Message().(type) { + case *types.Block: + server := ns.actualServer + server.BroadcastToListBlockStream(msg) + meta := msg.GetMetadata() + server.BroadcastToListBlockMetadataStream(meta) + case []*types.Event: + server := ns.actualServer + for _, e := range msg { + if bytes.Equal(e.GetContractAddress(), types.AddressPadding([]byte(types.AergoEnterprise))) { + eventName := strings.Split(e.GetEventName(), " ") + conf := strings.ToUpper(eventName[1]) + switch eventName[0] { + case "Enable": + if conf == enterprise.RPCPermissions { + value := false + if e.JsonArgs == "true" { + value = true + } + server.setClientAuthOn(value) + } else if conf == enterprise.AccountWhite { + value := false + if e.JsonArgs == "true" { + value = true + } + msg := &message.MemPoolEnableWhitelist{On: value} + ns.TellTo(message.MemPoolSvc, msg) + } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { + value := false + if e.JsonArgs == "true" { + value = true + } + msg := message.P2PWhiteListConfEnableEvent{Name: conf, On: value} + ns.TellTo(message.P2PSvc, msg) + } + case "Set": + if conf == enterprise.RPCPermissions { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + server.setClientAuthMap(values) + } else if conf == enterprise.AccountWhite { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + msg := &message.MemPoolSetWhitelist{ + Accounts: values, + } + ns.TellTo(message.MemPoolSvc, msg) + } else if conf == enterprise.P2PBlack || conf == enterprise.P2PWhite { + values := make([]string, 1024) + if err := json.Unmarshal([]byte(e.JsonArgs), &values); err != nil { + return + } + msg := message.P2PWhiteListConfSetEvent{ + Values: values, + } + ns.TellTo(message.P2PSvc, msg) + } + default: + logger.Warn().Str("Enterprise event", eventName[0]).Str("conf", conf).Msg("unknown message in RPCPERMISSION") + } + } + } + server.BroadcastToEventStream(msg) + case *message.GetServerInfo: + context.Respond(ns.CollectServerInfo(msg.Categories)) + case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing + // Ignore actor lfiecycle messages + default: + ns.Warn().Msgf("unknown msg received in rpc %s", reflect.TypeOf(msg).String()) + } +} + +// Create HTTP handler that redirects matching grpc-web requests to the grpc-web wrapper. +func (ns *RPC) grpcWebHandlerFunc(grpcWebServer *grpcweb.WrappedGrpcServer, otherHandler http.Handler, actualServer *AergoRPCService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if grpcWebServer.IsAcceptableGrpcCorsRequest(r) || grpcWebServer.IsGrpcWebRequest(r) || grpcWebServer.IsGrpcWebSocketRequest(r) { - grpcWebServer.ServeHTTP(w, r) + grpcWebServer.ServeHTTP(w, r) } else { ns.Info().Msg("Request handled by other hanlder. is this correct?") otherHandler.ServeHTTP(w, r) // handler, ok := restAPIHandler(actualServer, r) - + // if(ok) { // handler.ServeHTTP(w, r) // }else{ @@ -276,145 +276,144 @@ import ( // otherHandler.ServeHTTP(w, r) // } } - }) - } - - // Serve GRPC server over TCP - func (ns *RPC) serveGRPC(l net.Listener, server *grpc.Server) { - if err := server.Serve(l); err != nil { - switch err { - case cmux.ErrListenerClosed: - // Server killed, usually by ctrl-c signal - default: - panic(err) - } - } - } - - // Serve HTTP server over TCP - func (ns *RPC) serveHTTP(l net.Listener, server *http.Server) { - if err := server.Serve(l); err != nil && err != http.ErrServerClosed { - panic(err) - } - } - - // Serve TCP multiplexer - func (ns *RPC) serve() { - ipAddr := net.ParseIP(ns.conf.RPC.NetServiceAddr) - if ipAddr == nil { - panic("Wrong IP address format in RPC.NetServiceAddr") - } - - addr := fmt.Sprintf("%s:%d", ipAddr, ns.conf.RPC.NetServicePort) - - l, err := net.Listen("tcp", addr) - if err != nil { - panic(err) - } - - // Setup TCP multiplexer - tcpm := cmux.New(l) - - //grpcL := tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) - matchers := []cmux.Matcher{cmux.HTTP2()} - if ns.conf.RPC.NSEnableTLS { - matchers = append(matchers, cmux.TLS()) - } else { - //http1 only work without TLS - httpL := tcpm.Match(cmux.HTTP1Fast()) - go ns.serveHTTP(httpL, ns.httpServer) - } - grpcL := tcpm.Match(matchers...) - go ns.serveGRPC(grpcL, ns.grpcServer) - - ns.Info().Msg(fmt.Sprintf("Starting RPC server listening on %s, with TLS: %v", addr, ns.conf.RPC.NSEnableTLS)) - - // Serve TCP multiplexer - if err := tcpm.Serve(); !strings.Contains(err.Error(), "use of closed network connection") { - ns.Fatal().Msg(fmt.Sprintf("%v", err)) - } - - return - } - - func (ns *RPC) CollectServerInfo(categories []string) *types.ServerInfo { - // 3 items are needed - statusInfo := make(map[string]string) - rsp, err := ns.CallRequestDefaultTimeout(message.P2PSvc, &message.GetSelf{}) - statusInfo["version"] = ns.version - if err != nil { - ns.Logger.Error().Err(err).Msg("p2p actor error") - statusInfo["id"] = p2pkey.NodeSID() - } else { - meta := rsp.(p2pcommon.PeerMeta) - statusInfo["id"] = meta.ID.Pretty() - statusInfo["addr"] = meta.PrimaryAddress() - statusInfo["port"] = strconv.Itoa(int(meta.PrimaryPort())) - } - configInfo := make(map[string]*types.ConfigItem) - types.AddCategory(configInfo, "base").AddBool("personal", ns.conf.BaseConfig.Personal) - types.AddCategory(configInfo, "account").AddInt("unlocktimeout", int(ns.conf.Account.UnlockTimeout)) - return &types.ServerInfo{Status: statusInfo, Config: configInfo} - } - - const defaultTTL = time.Second * 4 - - // TellRequest implement interface method of ActorService - func (ns *RPC) TellRequest(actor string, msg interface{}) { - ns.TellTo(actor, msg) - } - - // SendRequest implement interface method of ActorService - func (ns *RPC) SendRequest(actor string, msg interface{}) { - ns.RequestTo(actor, msg) - } - - // FutureRequest implement interface method of ActorService - func (ns *RPC) FutureRequest(actor string, msg interface{}, timeout time.Duration) *actor.Future { - return ns.RequestToFuture(actor, msg, timeout) - } - - // FutureRequestDefaultTimeout implement interface method of ActorService - func (ns *RPC) FutureRequestDefaultTimeout(actor string, msg interface{}) *actor.Future { - return ns.RequestToFuture(actor, msg, defaultTTL) - } - - // CallRequest implement interface method of ActorService - func (ns *RPC) CallRequest(actor string, msg interface{}, timeout time.Duration) (interface{}, error) { - future := ns.RequestToFuture(actor, msg, timeout) - return future.Result() - } - - // CallRequest implement interface method of ActorService - func (ns *RPC) CallRequestDefaultTimeout(actor string, msg interface{}) (interface{}, error) { - future := ns.RequestToFuture(actor, msg, defaultTTL) - return future.Result() - } - - // GetChainAccessor implment interface method of ActorService - func (ns *RPC) GetChainAccessor() types.ChainAccessor { - return ns.ca - } - - func convertError(err error) types.CommitStatus { - switch err { - case nil: - return types.CommitStatus_TX_OK - case types.ErrTxNonceTooLow: - return types.CommitStatus_TX_NONCE_TOO_LOW - case types.ErrTxAlreadyInMempool: - return types.CommitStatus_TX_ALREADY_EXISTS - case types.ErrTxHasInvalidHash: - return types.CommitStatus_TX_INVALID_HASH - case types.ErrTxFormatInvalid: - return types.CommitStatus_TX_INVALID_FORMAT - case types.ErrInsufficientBalance: - return types.CommitStatus_TX_INSUFFICIENT_BALANCE - case types.ErrSameNonceAlreadyInMempool: - return types.CommitStatus_TX_HAS_SAME_NONCE - default: - //logger.Info().Str("hash", err.Error()).Msg("RPC encountered unconvertable error") - return types.CommitStatus_TX_INTERNAL_ERROR - } - } - \ No newline at end of file + }) +} + +// Serve GRPC server over TCP +func (ns *RPC) serveGRPC(l net.Listener, server *grpc.Server) { + if err := server.Serve(l); err != nil { + switch err { + case cmux.ErrListenerClosed: + // Server killed, usually by ctrl-c signal + default: + panic(err) + } + } +} + +// Serve HTTP server over TCP +func (ns *RPC) serveHTTP(l net.Listener, server *http.Server) { + if err := server.Serve(l); err != nil && err != http.ErrServerClosed { + panic(err) + } +} + +// Serve TCP multiplexer +func (ns *RPC) serve() { + ipAddr := net.ParseIP(ns.conf.RPC.NetServiceAddr) + if ipAddr == nil { + panic("Wrong IP address format in RPC.NetServiceAddr") + } + + addr := fmt.Sprintf("%s:%d", ipAddr, ns.conf.RPC.NetServicePort) + + l, err := net.Listen("tcp", addr) + if err != nil { + panic(err) + } + + // Setup TCP multiplexer + tcpm := cmux.New(l) + + //grpcL := tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) + matchers := []cmux.Matcher{cmux.HTTP2()} + if ns.conf.RPC.NSEnableTLS { + matchers = append(matchers, cmux.TLS()) + } else { + //http1 only work without TLS + httpL := tcpm.Match(cmux.HTTP1Fast()) + go ns.serveHTTP(httpL, ns.httpServer) + } + grpcL := tcpm.Match(matchers...) + go ns.serveGRPC(grpcL, ns.grpcServer) + + ns.Info().Msg(fmt.Sprintf("Starting RPC server listening on %s, with TLS: %v", addr, ns.conf.RPC.NSEnableTLS)) + + // Serve TCP multiplexer + if err := tcpm.Serve(); !strings.Contains(err.Error(), "use of closed network connection") { + ns.Fatal().Msg(fmt.Sprintf("%v", err)) + } + + return +} + +func (ns *RPC) CollectServerInfo(categories []string) *types.ServerInfo { + // 3 items are needed + statusInfo := make(map[string]string) + rsp, err := ns.CallRequestDefaultTimeout(message.P2PSvc, &message.GetSelf{}) + statusInfo["version"] = ns.version + if err != nil { + ns.Logger.Error().Err(err).Msg("p2p actor error") + statusInfo["id"] = p2pkey.NodeSID() + } else { + meta := rsp.(p2pcommon.PeerMeta) + statusInfo["id"] = meta.ID.Pretty() + statusInfo["addr"] = meta.PrimaryAddress() + statusInfo["port"] = strconv.Itoa(int(meta.PrimaryPort())) + } + configInfo := make(map[string]*types.ConfigItem) + types.AddCategory(configInfo, "base").AddBool("personal", ns.conf.BaseConfig.Personal) + types.AddCategory(configInfo, "account").AddInt("unlocktimeout", int(ns.conf.Account.UnlockTimeout)) + return &types.ServerInfo{Status: statusInfo, Config: configInfo} +} + +const defaultTTL = time.Second * 4 + +// TellRequest implement interface method of ActorService +func (ns *RPC) TellRequest(actor string, msg interface{}) { + ns.TellTo(actor, msg) +} + +// SendRequest implement interface method of ActorService +func (ns *RPC) SendRequest(actor string, msg interface{}) { + ns.RequestTo(actor, msg) +} + +// FutureRequest implement interface method of ActorService +func (ns *RPC) FutureRequest(actor string, msg interface{}, timeout time.Duration) *actor.Future { + return ns.RequestToFuture(actor, msg, timeout) +} + +// FutureRequestDefaultTimeout implement interface method of ActorService +func (ns *RPC) FutureRequestDefaultTimeout(actor string, msg interface{}) *actor.Future { + return ns.RequestToFuture(actor, msg, defaultTTL) +} + +// CallRequest implement interface method of ActorService +func (ns *RPC) CallRequest(actor string, msg interface{}, timeout time.Duration) (interface{}, error) { + future := ns.RequestToFuture(actor, msg, timeout) + return future.Result() +} + +// CallRequest implement interface method of ActorService +func (ns *RPC) CallRequestDefaultTimeout(actor string, msg interface{}) (interface{}, error) { + future := ns.RequestToFuture(actor, msg, defaultTTL) + return future.Result() +} + +// GetChainAccessor implment interface method of ActorService +func (ns *RPC) GetChainAccessor() types.ChainAccessor { + return ns.ca +} + +func convertError(err error) types.CommitStatus { + switch err { + case nil: + return types.CommitStatus_TX_OK + case types.ErrTxNonceTooLow: + return types.CommitStatus_TX_NONCE_TOO_LOW + case types.ErrTxAlreadyInMempool: + return types.CommitStatus_TX_ALREADY_EXISTS + case types.ErrTxHasInvalidHash: + return types.CommitStatus_TX_INVALID_HASH + case types.ErrTxFormatInvalid: + return types.CommitStatus_TX_INVALID_FORMAT + case types.ErrInsufficientBalance: + return types.CommitStatus_TX_INSUFFICIENT_BALANCE + case types.ErrSameNonceAlreadyInMempool: + return types.CommitStatus_TX_HAS_SAME_NONCE + default: + //logger.Info().Str("hash", err.Error()).Msg("RPC encountered unconvertable error") + return types.CommitStatus_TX_INTERNAL_ERROR + } +} diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index 023a002d4..48f7d3ef5 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -22,14 +22,14 @@ import ( ) type Web3APIv1 struct { - rpc *rpc.AergoRPCService + rpc *rpc.AergoRPCService request *http.Request } func (api *Web3APIv1) handler(w http.ResponseWriter, r *http.Request) { - api.request = r; - handler, ok := api.restAPIHandler(r) - if(ok) { + api.request = r + handler, ok := api.restAPIHandler(r) + if ok { handler.ServeHTTP(w, r) } else { http.NotFound(w, r) @@ -42,43 +42,77 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok if r.Method == http.MethodGet { switch path { - case "/getAccounts": return api.GetAccounts(); - case "/getState": return api.GetState(); - case "/getProof": return api.GetStateAndProof(); - case "/getNameInfo": return api.GetNameInfo(); - case "/getBalance": return api.GetBalance(); - case "/getBlock": return api.GetBlock(); - case "/getBlockNumber": return api.Blockchain(); - case "/getBlockBody": return api.GetBlockBody(); - case "/listBlockHeaders": return api.ListBlockHeaders(); - case "/getBlockMetadata": return api.GetBlockMetadata(); - case "/getTransaction": return api.GetTX(); - case "/getTransactionReceipt": return api.GetReceipt(); - case "/getBlockTransactionReceipts": return api.GetReceipts(); - case "/getBlockTX": return api.GetBlockTX(); - case "/call": return api.QueryContract(); - case "/getPastEvents": return api.ListEvents(); - case "/getABI": return api.GetABI(); - case "/queryContractState": return api.QueryContractState(); - case "/getBlockTransactionCount": return api.GetBlockTransactionCount(); - case "/getChainInfo": return api.GetChainInfo(); - case "/getConsensusInfo": return api.GetConsensusInfo(); - case "/getAccountVotes": return api.GetAccountVotes(); - case "/getNodeInfo": return api.NodeState(); - case "/getChainId": return api.GetPeers(); - case "/getServerInfo": return api.GetServerInfo(); - case "/getStaking": return api.GetStaking(); - case "/getVotes": return api.GetVotes(); - case "/metric": return api.Metric(); - case "/getEnterpriseConfig": return api.GetEnterpriseConfig(); - case "/getConfChangeProgress": return api.GetConfChangeProgress(); - case "/chainStat": return api.ChainStat(); - default: return nil, false + case "/getAccounts": + return api.GetAccounts() + case "/getState": + return api.GetState() + case "/getProof": + return api.GetStateAndProof() + case "/getNameInfo": + return api.GetNameInfo() + case "/getBalance": + return api.GetBalance() + case "/getBlock": + return api.GetBlock() + case "/getBlockNumber": + return api.Blockchain() + case "/getBlockBody": + return api.GetBlockBody() + case "/listBlockHeaders": + return api.ListBlockHeaders() + case "/getBlockMetadata": + return api.GetBlockMetadata() + case "/getTransaction": + return api.GetTX() + case "/getTransactionReceipt": + return api.GetReceipt() + case "/getBlockTransactionReceipts": + return api.GetReceipts() + case "/getBlockTX": + return api.GetBlockTX() + case "/call": + return api.QueryContract() + case "/getPastEvents": + return api.ListEvents() + case "/getABI": + return api.GetABI() + case "/queryContractState": + return api.QueryContractState() + case "/getBlockTransactionCount": + return api.GetBlockTransactionCount() + case "/getChainInfo": + return api.GetChainInfo() + case "/getConsensusInfo": + return api.GetConsensusInfo() + case "/getAccountVotes": + return api.GetAccountVotes() + case "/getNodeInfo": + return api.NodeState() + case "/getChainId": + return api.GetPeers() + case "/getServerInfo": + return api.GetServerInfo() + case "/getStaking": + return api.GetStaking() + case "/getVotes": + return api.GetVotes() + case "/metric": + return api.Metric() + case "/getEnterpriseConfig": + return api.GetEnterpriseConfig() + case "/getConfChangeProgress": + return api.GetConfChangeProgress() + case "/chainStat": + return api.ChainStat() + default: + return nil, false } } else if r.Method == http.MethodPost { switch path { - case "/sendSignedTransaction": return api.CommitTX(); - default: return nil, false + case "/sendSignedTransaction": + return api.CommitTX() + default: + return nil, false } } return nil, false @@ -86,11 +120,11 @@ func (api *Web3APIv1) restAPIHandler(r *http.Request) (handler http.Handler, ok func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { request := &types.Empty{} - + msg, err := api.rpc.GetAccounts(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } out := fmt.Sprintf("%s", "[") @@ -102,7 +136,7 @@ func (api *Web3APIv1) GetAccounts() (handler http.Handler, ok bool) { if addresslist != nil && len(out) >= 2 { out = out[:len(out)-2] } - } + } out = fmt.Sprintf("%s%s", out, "]") return stringResponseHandler(out, nil), true @@ -119,24 +153,24 @@ func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { if account != "" { accountBytes, err := types.DecodeAddress(account) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = accountBytes } - + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - msg, err := api.rpc.GetState(api.request.Context(), request); + msg, err := api.rpc.GetState(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } balance, err := util.ConvertUnit(msg.GetBalanceBigInt(), "aergo") if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } - + result := fmt.Sprintf(`{"account":"%s", "balance":"%s", "nonce":%d}`, account, balance, msg.GetNonce()) return stringResponseHandler(result, nil), true } @@ -152,7 +186,7 @@ func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { if account != "" { accountBytes, err := types.DecodeAddress(account) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Account = accountBytes } @@ -164,23 +198,23 @@ func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, parseErr), true } request.Compressed = compressedValue - } - + } + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - msg, err := api.rpc.GetStateAndProof(api.request.Context(), request); + msg, err := api.rpc.GetStateAndProof(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } balance, err := util.ConvertUnit(msg.GetState().GetBalanceBigInt(), "aergo") if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } - + result := fmt.Sprintf(`{"account":"%s", "nonce":%d, "balance":"%s", "included":%t, "merkle proof length":%d, "height":%d}`+"\n", - account, msg.GetState().GetNonce(), balance, msg.GetInclusion(), len(msg.GetAuditPath()), msg.GetHeight()) + account, msg.GetState().GetNonce(), balance, msg.GetInclusion(), len(msg.GetAuditPath()), msg.GetHeight()) return stringResponseHandler(result, nil), true } @@ -210,13 +244,13 @@ func (api *Web3APIv1) GetNameInfo() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - msg, err := api.rpc.GetNameInfo(api.request.Context(), request); + msg, err := api.rpc.GetNameInfo(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } result := fmt.Sprintf(`{"%s": {"Owner" : "%s", "Destination" : "%s" }}`, - msg.Name.Name, types.EncodeAddress(msg.Owner), types.EncodeAddress(msg.Destination)) + msg.Name.Name, types.EncodeAddress(msg.Owner), types.EncodeAddress(msg.Destination)) return stringResponseHandler(result, nil), true } @@ -232,42 +266,41 @@ func (api *Web3APIv1) GetBalance() (handler http.Handler, ok bool) { if account != "" { accountBytes, err := types.DecodeAddress(account) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = accountBytes } - + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - msg, err := api.rpc.GetState(api.request.Context(), request); + msg, err := api.rpc.GetState(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } result := fmt.Sprintf(`{"balance":"%s"}`, msg.GetBalanceBigInt()) return stringResponseHandler(result, nil), true } - func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + // Params request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } - + number := values.Get("number") if number != "" { numberValue, err := strconv.ParseUint(number, 10, 64) @@ -287,7 +320,7 @@ func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { result, err := api.rpc.GetBlock(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true @@ -298,19 +331,18 @@ func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + // Params request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } - number := values.Get("number") if number != "" { numberValue, err := strconv.ParseUint(number, 10, 64) @@ -332,7 +364,7 @@ func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + result := fmt.Sprintf(`{"count":"%d"}`, func() int { if msg.Body.Txs != nil { return len(msg.Body.Txs) @@ -343,7 +375,6 @@ func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) return stringResponseHandler(result, nil), true } - func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { ca := api.rpc.GetActorHelper().GetChainAccessor() last, err := ca.GetBestBlock() @@ -360,7 +391,7 @@ func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { logger.Warn().Err(err).Msg("failed to get chain info in blockchain") chainInfo = nil } - + result := &types.BlockchainStatus{ BestBlockHash: last.BlockHash(), BestHeight: last.GetHeader().GetBlockNo(), @@ -386,11 +417,11 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Hashornumber = hashBytes } - + number := values.Get("number") if number != "" { numberValue, err := strconv.ParseUint(number, 10, 64) @@ -402,15 +433,15 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { binary.LittleEndian.PutUint64(byteValue, number) request.Hashornumber = byteValue } - + size := values.Get("size") if size != "" { sizeValue, parseErr := strconv.ParseUint(size, 10, 64) if parseErr != nil { return commonResponseHandler(&types.Empty{}, parseErr), true - + } - request.Paging.Size = uint32(sizeValue) + request.Paging.Size = uint32(sizeValue) } offset := values.Get("offset") @@ -421,7 +452,7 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { } request.Paging.Offset = uint32(offsetValue) } - + // Validate if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -429,7 +460,7 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { result, err := api.rpc.GetBlockBody(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true @@ -486,7 +517,7 @@ func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { result, err := api.rpc.ListBlockHeaders(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true @@ -504,12 +535,11 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } - number := values.Get("number") if number != "" { numberValue, err := strconv.ParseUint(number, 10, 64) @@ -529,7 +559,7 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { result, err := api.rpc.GetBlockMetadata(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true @@ -584,7 +614,6 @@ func (api *Web3APIv1) ListBlockMetadata() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.ListBlockMetadata(api.request.Context(), request)), true } - func (api *Web3APIv1) GetChainInfo() (handler http.Handler, ok bool) { request := &types.Empty{} return commonResponseHandler(api.rpc.GetChainInfo(api.request.Context(), request)), true @@ -600,7 +629,6 @@ func (api *Web3APIv1) GetConsensusInfo() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.GetConsensusInfo(api.request.Context(), request)), true } - func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { @@ -612,7 +640,7 @@ func (api *Web3APIv1) GetReceipt() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -634,11 +662,11 @@ func (api *Web3APIv1) GetReceipts() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } - + number := values.Get("number") if number != "" { numberValue, err := strconv.ParseUint(number, 10, 64) @@ -657,7 +685,7 @@ func (api *Web3APIv1) GetReceipts() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.GetReceipts(api.request.Context(), request)), true } -func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -668,7 +696,7 @@ func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -684,14 +712,14 @@ func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return commonResponseHandler(util.ConvTxInBlockEx(msgblock, util.Base58), nil), true } } -func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -702,7 +730,7 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base58.Decode(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -714,7 +742,7 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { msg, err := api.rpc.GetTX(api.request.Context(), request) if err == nil { return commonResponseHandler(util.ConvTxEx(msg, util.Base58), nil), true - + } else { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { @@ -724,18 +752,18 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { } } -func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { +func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + request := &types.Query{} address := values.Get("address") if address != "" { hashBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.ContractAddress = hashBytes } @@ -745,32 +773,32 @@ func (api *Web3APIv1) QueryContract() (handler http.Handler, ok bool) { if name != "" { ci.Name = name } - + query := values.Get("query") - - if query != "" { + + if query != "" { err = json.Unmarshal([]byte(query), &ci.Args) if err != nil { return commonResponseHandler(&types.Empty{}, err), true - } + } } callinfo, err := json.Marshal(ci) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } - - request.Queryinfo = callinfo; + + request.Queryinfo = callinfo if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } msg, err := api.rpc.QueryContract(api.request.Context(), request) - return stringResponseHandler("{\"result\":" + string(msg.Value) + "}", nil), true + return stringResponseHandler("{\"result\":"+string(msg.Value)+"}", nil), true } -func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { +func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -781,7 +809,7 @@ func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { if address != "" { hashBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.ContractAddress = hashBytes } @@ -797,7 +825,7 @@ func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - request.Blockfrom = uint64(BlockfromValue) + request.Blockfrom = uint64(BlockfromValue) } Blockto := values.Get("Blockto") @@ -806,7 +834,7 @@ func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - request.Blockto = uint64(BlocktoValue) + request.Blockto = uint64(BlocktoValue) } desc := values.Get("desc") @@ -830,10 +858,10 @@ func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, parseErr), true } request.RecentBlockCnt = int32(recentBlockCntValue) - }else{ + } else { request.RecentBlockCnt = 0 } - + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -841,7 +869,7 @@ func (api *Web3APIv1) ListEvents() (handler http.Handler, ok bool) { return commonResponseHandler(api.rpc.ListEvents(api.request.Context(), request)), true } -func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -853,7 +881,7 @@ func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { if address != "" { hashBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -862,11 +890,11 @@ func (api *Web3APIv1) GetABI() (handler http.Handler, ok bool) { if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + return commonResponseHandler(api.rpc.GetABI(api.request.Context(), request)), true } -func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -877,7 +905,7 @@ func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { if address != "" { hashBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -886,11 +914,11 @@ func (api *Web3APIv1) GetAccountVotes() (handler http.Handler, ok bool) { if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + return commonResponseHandler(api.rpc.GetAccountVotes(api.request.Context(), request)), true } -func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { +func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -901,12 +929,12 @@ func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { if address != "" { addressBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.ContractAddress = addressBytes } - storageKeyPlain := bytes.NewBufferString("_sv_") + storageKeyPlain := bytes.NewBufferString("_sv_") args1 := values.Get("varname1") if args1 != "" { storageKeyPlain.WriteString(args1) @@ -916,7 +944,7 @@ func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { storageKeyPlain.WriteString("-") storageKeyPlain.WriteString(args2) } - + storageKey := common.Hasher([]byte(storageKeyPlain.Bytes())) request.StorageKeys = [][]byte{storageKey} @@ -932,16 +960,16 @@ func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + result, err := api.rpc.QueryContractState(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(util.JSON(result), nil), true } -func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { +func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -971,10 +999,10 @@ func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { msg, err := api.rpc.NodeState(api.request.Context(), request) - return stringResponseHandler(string(msg.Value), nil), true + return stringResponseHandler(string(msg.Value), nil), true } -func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -1005,13 +1033,13 @@ func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { result, err := api.rpc.GetPeers(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true } -func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -1029,13 +1057,13 @@ func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { result, err := api.rpc.GetServerInfo(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true } -func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -1046,7 +1074,7 @@ func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { if address != "" { addressBytes, err := types.DecodeAddress(address) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = addressBytes } @@ -1054,7 +1082,7 @@ func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + return commonResponseHandler(api.rpc.GetStaking(api.request.Context(), request)), true } @@ -1066,7 +1094,7 @@ func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { request := &types.VoteParams{} request.Id = types.OpvoteBP.ID() - + count := values.Get("count") if count != "" { sizeValue, parseErr := strconv.ParseUint(count, 10, 32) @@ -1075,14 +1103,14 @@ func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { } request.Count = uint32(sizeValue) } - + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } msg, err := api.rpc.GetVotes(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } result := "[" @@ -1095,8 +1123,8 @@ func (api *Web3APIv1) GetVotes() (handler http.Handler, ok bool) { result = result + comma } result = result + "]" - - return stringResponseHandler(result, nil), true + + return stringResponseHandler(result, nil), true } func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { @@ -1112,20 +1140,20 @@ func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { request.Types = append(request.Types, types.MetricType(types.MetricType_value[metricType])) } - // Validate + // Validate if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } result, err := api.rpc.Metric(api.request.Context(), request) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } return stringResponseHandler(util.JSON(result), nil), true } -func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { +func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { values, err := url.ParseQuery(api.request.URL.RawQuery) if err != nil { return commonResponseHandler(&types.Empty{}, err), true @@ -1137,7 +1165,7 @@ func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { if key != "" { request.Key = key } - + if _, err := govalidator.ValidateStruct(request); err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -1159,8 +1187,8 @@ func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { if strings.ToUpper(key) != "PERMISSIONS" { out.On = &msg.On } - - return stringResponseHandler(util.B58JSON(out), nil), true + + return stringResponseHandler(util.B58JSON(out), nil), true } func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { @@ -1174,7 +1202,7 @@ func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { if hash != "" { hashBytes, err := base64.StdEncoding.DecodeString(hash) if err != nil { - return commonResponseHandler(&types.Empty{}, err), true + return commonResponseHandler(&types.Empty{}, err), true } request.Value = hashBytes } @@ -1191,7 +1219,7 @@ func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, block.BlockNo()) - return commonResponseHandler(api.rpc.GetConfChangeProgress(api.request.Context(), &types.SingleBytes{Value: b})), true + return commonResponseHandler(api.rpc.GetConfChangeProgress(api.request.Context(), &types.SingleBytes{Value: b})), true } func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { @@ -1199,12 +1227,11 @@ func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + txs, err := util.ParseBase58Tx([]byte(body)) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - + return commonResponseHandler(api.rpc.CommitTX(api.request.Context(), &types.TxList{Txs: txs})), true } - diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index e584c2c96..d47d42b2a 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -16,7 +16,7 @@ import ( ) type RestAPI struct { - rpc *rpc.AergoRPCService + rpc *rpc.AergoRPCService request *http.Request } @@ -30,33 +30,33 @@ var ( func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { mux := http.NewServeMux() - + // set limit per second maxLimit := float64(1) - if cfg.Web3.MaxLimit != 0 { + if cfg.Web3.MaxLimit != 0 { maxLimit = float64(cfg.Web3.MaxLimit) } limiter := tollbooth.NewLimiter(maxLimit, nil) - limiter.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}) + limiter.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}) // swagger mux.HandleFunc("/swagger.yaml", serveSwaggerYAML) mux.HandleFunc("/swagger", serveSwaggerUI) c := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{"GET", "POST"}, - AllowedHeaders: []string{"*"}, + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST"}, + AllowedHeaders: []string{"*"}, AllowCredentials: true, }) - + // API v1 web3svcV1 := &Web3APIv1{rpc: rpc} mux.Handle("/v1/", tollbooth.LimitHandler(limiter, c.Handler(http.HandlerFunc(web3svcV1.handler)))) - go func() { - fmt.Println("Web3 Server is listening on port "+ strconv.Itoa(cfg.Web3.NetServicePort)+"...") + go func() { + fmt.Println("Web3 Server is listening on port " + strconv.Itoa(cfg.Web3.NetServicePort) + "...") http.ListenAndServe(":"+strconv.Itoa(cfg.Web3.NetServicePort), mux) }() } @@ -96,7 +96,6 @@ func commonResponseHandler(response interface{}, err error) http.Handler { return } - w.Header().Set("Content-Type", "application/json") w.Write(jsonResponse) }) @@ -119,4 +118,3 @@ func stringResponseHandler(response string, err error) http.Handler { w.Write([]byte(response)) }) } - diff --git a/rpc/web3/web3_test.go b/rpc/web3/web3_test.go index d075f824e..2a40b6efe 100644 --- a/rpc/web3/web3_test.go +++ b/rpc/web3/web3_test.go @@ -8,7 +8,7 @@ import ( func TestRateLimitMiddleware(t *testing.T) { url := "http://localhost/v1/getBlock?number=1" - + req, err := http.NewRequest("GET", url, nil) if err != nil { t.Fatal(err) @@ -31,4 +31,4 @@ func TestRateLimitMiddleware(t *testing.T) { time.Sleep(100 * time.Millisecond) } -} \ No newline at end of file +} From 21856f8993943475369654e87600f7f33872a61a Mon Sep 17 00:00:00 2001 From: gokch Date: Thu, 2 Nov 2023 08:01:59 +0000 Subject: [PATCH 013/134] fix error tests --- config/config.go | 8 ++++++++ rpc/web3/web3_test.go | 3 +++ 2 files changed, 11 insertions(+) diff --git a/config/config.go b/config/config.go index d0dec82e8..b135806f8 100644 --- a/config/config.go +++ b/config/config.go @@ -42,6 +42,7 @@ func (ctx *ServerContext) GetDefaultConfig() interface{} { return &Config{ BaseConfig: ctx.GetDefaultBaseConfig(), RPC: ctx.GetDefaultRPCConfig(), + Web3: ctx.GetDefaultWeb3Config(), P2P: ctx.GetDefaultP2PConfig(), Blockchain: ctx.GetDefaultBlockchainConfig(), Mempool: ctx.GetDefaultMempoolConfig(), @@ -78,6 +79,13 @@ func (ctx *ServerContext) GetDefaultRPCConfig() *RPCConfig { } } +func (ctx *ServerContext) GetDefaultWeb3Config() *Web3Config { + return &Web3Config{ + NetServicePort: 7847, + MaxLimit: 0, + } +} + func (ctx *ServerContext) GetDefaultP2PConfig() *P2PConfig { return &P2PConfig{ NetProtocolAddr: "", diff --git a/rpc/web3/web3_test.go b/rpc/web3/web3_test.go index 2a40b6efe..6606036e8 100644 --- a/rpc/web3/web3_test.go +++ b/rpc/web3/web3_test.go @@ -1,5 +1,7 @@ package web3 +// TODO : make mock server or remove +/* import ( "net/http" "testing" @@ -32,3 +34,4 @@ func TestRateLimitMiddleware(t *testing.T) { time.Sleep(100 * time.Millisecond) } } +*/ From 993739aa4d93ef06c63bfae5c24a6f082843b547 Mon Sep 17 00:00:00 2001 From: gokch Date: Thu, 2 Nov 2023 08:11:25 +0000 Subject: [PATCH 014/134] rollback protobuf submodule --- aergo-protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aergo-protobuf b/aergo-protobuf index 1d56e9d51..0c3579cd4 160000 --- a/aergo-protobuf +++ b/aergo-protobuf @@ -1 +1 @@ -Subproject commit 1d56e9d512e101ecd9aea5809c56015205f0b4ee +Subproject commit 0c3579cd42f830eb787715a78895d971b8ee5fce From 4dc06289344eb4642a3e0e6dfd7d3f57c1d77d68 Mon Sep 17 00:00:00 2001 From: gokch Date: Thu, 2 Nov 2023 09:06:40 +0000 Subject: [PATCH 015/134] move cmd/aergocli/util to types/jsonrpc --- cmd/aergocli/cmd/accounts.go | 3 +- cmd/aergocli/cmd/blockchain.go | 6 +-- cmd/aergocli/cmd/blockchain_test.go | 2 +- cmd/aergocli/cmd/chaininfo.go | 4 +- cmd/aergocli/cmd/committx.go | 10 ++--- cmd/aergocli/cmd/committx_test.go | 2 +- cmd/aergocli/cmd/contract.go | 20 ++++----- cmd/aergocli/cmd/enterprise.go | 6 +-- cmd/aergocli/cmd/event.go | 6 +-- cmd/aergocli/cmd/getblock.go | 6 +-- cmd/aergocli/cmd/getpeers.go | 8 ++-- cmd/aergocli/cmd/getstate.go | 8 ++-- cmd/aergocli/cmd/gettx.go | 10 ++--- cmd/aergocli/cmd/listblocks.go | 4 +- cmd/aergocli/cmd/mempool.go | 4 +- cmd/aergocli/cmd/metric.go | 4 +- cmd/aergocli/cmd/name.go | 6 +-- cmd/aergocli/cmd/receipt.go | 4 +- cmd/aergocli/cmd/root.go | 7 ++- cmd/aergocli/cmd/root_test.go | 4 +- cmd/aergocli/cmd/sendtx.go | 8 ++-- cmd/aergocli/cmd/sendtx_test.go | 2 +- cmd/aergocli/cmd/signtx.go | 12 +++--- cmd/aergocli/cmd/signtx_test.go | 6 +-- cmd/aergocli/cmd/stake.go | 4 +- cmd/aergocli/cmd/vote.go | 4 +- cmd/colaris/cmd/blacklist.go | 4 +- cmd/colaris/cmd/common.go | 2 +- cmd/colaris/cmd/current.go | 8 ++-- cmd/colaris/cmd/metric.go | 4 +- consensus/impl/raftv2/cluster.go | 4 +- mempool/mempool_test.go | 2 +- rpc/web3/v1.go | 40 +++++++++--------- rpc/web3/web3.go | 9 ++-- tools/mpdumpdiag/main.go | 11 +++-- .../util => types/jsonrpc}/base58addr.go | 2 +- .../util => types/jsonrpc}/base58addr_test.go | 2 +- .../util => types/jsonrpc}/base64ToHex.go | 2 +- .../util => types/jsonrpc}/convChaininfo.go | 2 +- .../aergocli/util => types/jsonrpc}/convTx.go | 2 +- .../util => types/jsonrpc}/convTx_test.go | 2 +- .../jsonrpc}/encoding/encoding.go | 0 .../jsonrpc}/encoding/json/decode.go | 0 .../jsonrpc}/encoding/json/decode_test.go | 0 .../jsonrpc}/encoding/json/encode.go | 0 .../jsonrpc}/encoding/json/encode_test.go | 0 .../encoding/json/example_marshaling_test.go | 0 .../jsonrpc}/encoding/json/example_test.go | 0 .../jsonrpc}/encoding/json/fold.go | 0 .../jsonrpc}/encoding/json/fold_test.go | 0 .../jsonrpc}/encoding/json/indent.go | 0 .../jsonrpc}/encoding/json/number_test.go | 0 .../jsonrpc}/encoding/json/scanner.go | 0 .../jsonrpc}/encoding/json/scanner_test.go | 0 .../jsonrpc}/encoding/json/stream.go | 0 .../jsonrpc}/encoding/json/stream_test.go | 0 .../jsonrpc}/encoding/json/tables.go | 0 .../jsonrpc}/encoding/json/tagkey_test.go | 0 .../jsonrpc}/encoding/json/tags.go | 0 .../jsonrpc}/encoding/json/tags_test.go | 0 .../encoding/json/testdata/code.json.gz | Bin .../util => types/jsonrpc}/grpccommon.go | 4 +- {cmd/aergocli/util => types/jsonrpc}/unit.go | 2 +- .../util => types/jsonrpc}/unit_test.go | 2 +- 64 files changed, 129 insertions(+), 135 deletions(-) rename {cmd/aergocli/util => types/jsonrpc}/base58addr.go (99%) rename {cmd/aergocli/util => types/jsonrpc}/base58addr_test.go (99%) rename {cmd/aergocli/util => types/jsonrpc}/base64ToHex.go (97%) rename {cmd/aergocli/util => types/jsonrpc}/convChaininfo.go (99%) rename {cmd/aergocli/util => types/jsonrpc}/convTx.go (99%) rename {cmd/aergocli/util => types/jsonrpc}/convTx_test.go (97%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/encoding.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/decode.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/decode_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/encode.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/encode_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/example_marshaling_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/example_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/fold.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/fold_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/indent.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/number_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/scanner.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/scanner_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/stream.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/stream_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/tables.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/tagkey_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/tags.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/tags_test.go (100%) rename {cmd/aergocli/util => types/jsonrpc}/encoding/json/testdata/code.json.gz (100%) rename {cmd/aergocli/util => types/jsonrpc}/grpccommon.go (94%) rename {cmd/aergocli/util => types/jsonrpc}/unit.go (99%) rename {cmd/aergocli/util => types/jsonrpc}/unit_test.go (99%) diff --git a/cmd/aergocli/cmd/accounts.go b/cmd/aergocli/cmd/accounts.go index 69fe50e0c..6c9f10bd9 100644 --- a/cmd/aergocli/cmd/accounts.go +++ b/cmd/aergocli/cmd/accounts.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "os" "path/filepath" @@ -237,7 +236,7 @@ func importKeystore(cmd *cobra.Command) ([]byte, error) { if err != nil { return nil, err } - keystore, err := ioutil.ReadFile(absPath) + keystore, err := os.ReadFile(absPath) if err != nil { return nil, err } diff --git a/cmd/aergocli/cmd/blockchain.go b/cmd/aergocli/cmd/blockchain.go index 0e5b4a579..b5bc476bd 100644 --- a/cmd/aergocli/cmd/blockchain.go +++ b/cmd/aergocli/cmd/blockchain.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -30,9 +30,9 @@ var blockchainCmd = &cobra.Command{ return } if printHex { - cmd.Println(util.ConvHexBlockchainStatus(msg)) + cmd.Println(jsonrpc.ConvHexBlockchainStatus(msg)) } else { - cmd.Println(util.ConvBlockchainStatus(msg)) + cmd.Println(jsonrpc.ConvBlockchainStatus(msg)) } }, } diff --git a/cmd/aergocli/cmd/blockchain_test.go b/cmd/aergocli/cmd/blockchain_test.go index 112fb0dc2..912a0d2bd 100644 --- a/cmd/aergocli/cmd/blockchain_test.go +++ b/cmd/aergocli/cmd/blockchain_test.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "testing" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/golang/mock/gomock" "github.com/mr-tron/base58/base58" "github.com/stretchr/testify/assert" diff --git a/cmd/aergocli/cmd/chaininfo.go b/cmd/aergocli/cmd/chaininfo.go index fce5e3b90..112da2158 100644 --- a/cmd/aergocli/cmd/chaininfo.go +++ b/cmd/aergocli/cmd/chaininfo.go @@ -3,8 +3,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -21,6 +21,6 @@ var chaininfoCmd = &cobra.Command{ cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(util.ConvChainInfoMsg(msg)) + cmd.Println(jsonrpc.ConvChainInfoMsg(msg)) }, } diff --git a/cmd/aergocli/cmd/committx.go b/cmd/aergocli/cmd/committx.go index 9dbdfd8a2..6764d7ba1 100644 --- a/cmd/aergocli/cmd/committx.go +++ b/cmd/aergocli/cmd/committx.go @@ -8,10 +8,10 @@ package cmd import ( "context" "errors" - "io/ioutil" + "os" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -50,7 +50,7 @@ func init() { func execCommitTX(cmd *cobra.Command, args []string) error { if jsonPath != "" { - b, readerr := ioutil.ReadFile(jsonPath) + b, readerr := os.ReadFile(jsonPath) if readerr != nil { return errors.New("Failed to read --jsontxpath\n" + readerr.Error()) } @@ -59,7 +59,7 @@ func execCommitTX(cmd *cobra.Command, args []string) error { if jsonTx != "" { var msg *types.CommitResultList - txlist, err := util.ParseBase58Tx([]byte(jsonTx)) + txlist, err := jsonrpc.ParseBase58Tx([]byte(jsonTx)) if err != nil { return errors.New("Failed to parse --jsontx\n" + err.Error()) } @@ -67,7 +67,7 @@ func execCommitTX(cmd *cobra.Command, args []string) error { if err != nil { return errors.New("Failed request to aergo server\n" + err.Error()) } - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) } return nil } diff --git a/cmd/aergocli/cmd/committx_test.go b/cmd/aergocli/cmd/committx_test.go index 27f3de136..1d902a886 100644 --- a/cmd/aergocli/cmd/committx_test.go +++ b/cmd/aergocli/cmd/committx_test.go @@ -3,8 +3,8 @@ package cmd import ( "testing" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/golang/mock/gomock" "github.com/mr-tron/base58/base58" "github.com/stretchr/testify/assert" diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 0e8bbb2aa..ab2030fd2 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -7,21 +7,21 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "os" "strconv" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" luacEncoding "github.com/aergoio/aergo/v2/cmd/aergoluac/encoding" luac "github.com/aergoio/aergo/v2/cmd/aergoluac/util" "github.com/aergoio/aergo/v2/internal/common" "github.com/aergoio/aergo/v2/types" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) var ( - client *util.ConnClient + client *jsonrpc.ConnClient admClient types.AdminRPCServiceClient data string nonce uint64 @@ -170,12 +170,12 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = false return errors.New("not enough arguments") } - code, err = ioutil.ReadFile(args[1]) + code, err = os.ReadFile(args[1]) if err != nil { return fmt.Errorf("failed to read code file: %v", err.Error()) } var abi []byte - abi, err = ioutil.ReadFile(args[2]) + abi, err = os.ReadFile(args[2]) if err != nil { return fmt.Errorf("failed to read abi file: %v", err.Error()) } @@ -212,7 +212,7 @@ func runDeployCmd(cmd *cobra.Command, args []string) error { } } - amountBigInt, err := util.ParseUnit(amount) + amountBigInt, err := jsonrpc.ParseUnit(amount) if err != nil { return fmt.Errorf("failed to parse amount: %v", err.Error()) } @@ -284,7 +284,7 @@ func runCallCmd(cmd *cobra.Command, args []string) error { } } - amountBigInt, err := util.ParseUnit(amount) + amountBigInt, err := jsonrpc.ParseUnit(amount) if err != nil { return fmt.Errorf("failed to parse amount: %v", err) } @@ -342,7 +342,7 @@ func runCallCmd(cmd *cobra.Command, args []string) error { } if toJSON { - cmd.Println(util.TxConvBase58Addr(tx)) + cmd.Println(jsonrpc.TxConvBase58Addr(tx)) } else { txs := []*types.Tx{tx} var msgs *types.CommitResultList @@ -350,7 +350,7 @@ func runCallCmd(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to commit tx: %v", err.Error()) } - cmd.Println(util.JSON(msgs.Results[0])) + cmd.Println(jsonrpc.JSON(msgs.Results[0])) } return nil } @@ -366,7 +366,7 @@ func runGetABICmd(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to get abi: %v", err.Error()) } - cmd.Println(util.JSON(abi)) + cmd.Println(jsonrpc.JSON(abi)) return nil } diff --git a/cmd/aergocli/cmd/enterprise.go b/cmd/aergocli/cmd/enterprise.go index ad24bfd40..14fab1725 100644 --- a/cmd/aergocli/cmd/enterprise.go +++ b/cmd/aergocli/cmd/enterprise.go @@ -13,11 +13,11 @@ import ( "strings" "time" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/contract/enterprise" "github.com/aergoio/aergo/v2/types" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -67,7 +67,7 @@ var enterpriseKeyCmd = &cobra.Command{ if strings.ToUpper(args[0]) != "PERMISSIONS" { out.On = &msg.On //it's for print false } - cmd.Println(util.B58JSON(out)) + cmd.Println(jsonrpc.B58JSON(out)) }, } diff --git a/cmd/aergocli/cmd/event.go b/cmd/aergocli/cmd/event.go index 41d8dc2dd..bfcd087ec 100644 --- a/cmd/aergocli/cmd/event.go +++ b/cmd/aergocli/cmd/event.go @@ -9,8 +9,8 @@ import ( "context" "log" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -82,7 +82,7 @@ func execListEvent(cmd *cobra.Command, args []string) { return } for _, event := range events.GetEvents() { - cmd.Println(util.JSON(event)) + cmd.Println(jsonrpc.JSON(event)) } } @@ -108,6 +108,6 @@ func execStreamEvent(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(util.JSON(event)) + cmd.Println(jsonrpc.JSON(event)) } } diff --git a/cmd/aergocli/cmd/getblock.go b/cmd/aergocli/cmd/getblock.go index 6f29340b0..9620a1024 100644 --- a/cmd/aergocli/cmd/getblock.go +++ b/cmd/aergocli/cmd/getblock.go @@ -11,8 +11,8 @@ import ( "errors" "fmt" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -45,7 +45,7 @@ func streamBlocks(cmd *cobra.Command) error { if err != nil { return fmt.Errorf("failed to receive block: %v", err) } - cmd.Println(util.BlockConvBase58Addr(b)) + cmd.Println(jsonrpc.BlockConvBase58Addr(b)) } } @@ -70,7 +70,7 @@ func getSingleBlock(cmd *cobra.Command) error { if err != nil { return fmt.Errorf("failed to get block: %v", err) } - cmd.Println(util.BlockConvBase58Addr(msg)) + cmd.Println(jsonrpc.BlockConvBase58Addr(msg)) return nil } diff --git a/cmd/aergocli/cmd/getpeers.go b/cmd/aergocli/cmd/getpeers.go index 571313eac..899055010 100644 --- a/cmd/aergocli/cmd/getpeers.go +++ b/cmd/aergocli/cmd/getpeers.go @@ -12,8 +12,8 @@ import ( "sort" "strings" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -59,12 +59,12 @@ func execGetPeers(cmd *cobra.Command, args []string) { // address and peerid should be encoded, respectively sorter.Sort(msg.Peers) if detailed == 0 { - cmd.Println(util.PeerListToString(msg)) + cmd.Println(jsonrpc.PeerListToString(msg)) } else if detailed > 0 { // TODO show long fields - cmd.Println(util.LongPeerListToString(msg)) + cmd.Println(jsonrpc.LongPeerListToString(msg)) } else { - cmd.Println(util.ShortPeerListToString(msg)) + cmd.Println(jsonrpc.ShortPeerListToString(msg)) } } diff --git a/cmd/aergocli/cmd/getstate.go b/cmd/aergocli/cmd/getstate.go index a2b02c3eb..8cb085329 100644 --- a/cmd/aergocli/cmd/getstate.go +++ b/cmd/aergocli/cmd/getstate.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -53,7 +53,7 @@ func execGetState(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - amount, err := util.ConvertUnit(msg.GetAmountBigInt(), unit) + amount, err := jsonrpc.ConvertUnit(msg.GetAmountBigInt(), unit) if err != nil { cmd.Printf("Failed: %s", err.Error()) return @@ -73,7 +73,7 @@ func execGetState(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - balance, err := util.ConvertUnit(msg.GetBalanceBigInt(), unit) + balance, err := jsonrpc.ConvertUnit(msg.GetBalanceBigInt(), unit) if err != nil { cmd.Printf("Failed: %s", err.Error()) return @@ -89,7 +89,7 @@ func execGetState(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - balance, err := util.ConvertUnit(msg.GetState().GetBalanceBigInt(), unit) + balance, err := jsonrpc.ConvertUnit(msg.GetState().GetBalanceBigInt(), unit) if err != nil { cmd.Printf("Failed: %s", err.Error()) return diff --git a/cmd/aergocli/cmd/gettx.go b/cmd/aergocli/cmd/gettx.go index a9f7f8d8e..962096b56 100644 --- a/cmd/aergocli/cmd/gettx.go +++ b/cmd/aergocli/cmd/gettx.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -35,20 +35,20 @@ func execGetTX(cmd *cobra.Command, args []string) { cmd.Printf("Failed decode: %s", err.Error()) return } - payloadEncodingType := util.Base58 + payloadEncodingType := jsonrpc.Base58 if rawPayload { - payloadEncodingType = util.Raw + payloadEncodingType = jsonrpc.Raw } msg, err := client.GetTX(context.Background(), &aergorpc.SingleBytes{Value: txHash}) if err == nil { - cmd.Println(util.ConvTxEx(msg, payloadEncodingType)) + cmd.Println(jsonrpc.ConvTxEx(msg, payloadEncodingType)) } else { msgblock, err := client.GetBlockTX(context.Background(), &aergorpc.SingleBytes{Value: txHash}) if err != nil { cmd.Printf("Failed: %s", err.Error()) return } - cmd.Println(util.ConvTxInBlockEx(msgblock, payloadEncodingType)) + cmd.Println(jsonrpc.ConvTxInBlockEx(msgblock, payloadEncodingType)) } } diff --git a/cmd/aergocli/cmd/listblocks.go b/cmd/aergocli/cmd/listblocks.go index d20a32385..1eb944069 100644 --- a/cmd/aergocli/cmd/listblocks.go +++ b/cmd/aergocli/cmd/listblocks.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -64,5 +64,5 @@ func execListBlockHeaders(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) } diff --git a/cmd/aergocli/cmd/mempool.go b/cmd/aergocli/cmd/mempool.go index 846d80a79..0dd9a4b37 100644 --- a/cmd/aergocli/cmd/mempool.go +++ b/cmd/aergocli/cmd/mempool.go @@ -6,8 +6,8 @@ import ( "log" "strings" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" "google.golang.org/grpc" ) @@ -77,6 +77,6 @@ func newAergoAdminClient(sockPath string) types.AdminRPCServiceClient { grpc.WithInsecure(), } return types.NewAdminRPCServiceClient( - util.GetConn(fmt.Sprintf("unix:%s", sockPath), opts), + jsonrpc.GetConn(fmt.Sprintf("unix:%s", sockPath), opts), ) } diff --git a/cmd/aergocli/cmd/metric.go b/cmd/aergocli/cmd/metric.go index a18268a12..94670ca76 100644 --- a/cmd/aergocli/cmd/metric.go +++ b/cmd/aergocli/cmd/metric.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -40,5 +40,5 @@ func execMetric(cmd *cobra.Command, args []string) { return } // address and peerid should be encoded, respectively - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) } diff --git a/cmd/aergocli/cmd/name.go b/cmd/aergocli/cmd/name.go index 68b065ef1..82d4338ff 100644 --- a/cmd/aergocli/cmd/name.go +++ b/cmd/aergocli/cmd/name.go @@ -13,8 +13,8 @@ import ( "log" "math/big" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -77,7 +77,7 @@ func execNameNew(cmd *cobra.Command, args []string) error { if len(name) != types.NameLength { return errors.New("the name must be 12 alphabetic characters") } - amount, err := util.ParseUnit(spending) + amount, err := jsonrpc.ParseUnit(spending) if err != nil { return fmt.Errorf("wrong value in --amount flag: %v", err.Error()) } @@ -114,7 +114,7 @@ func execNameUpdate(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("Wrong address in --to flag: %v", err.Error()) } - amount, err := util.ParseUnit(spending) + amount, err := jsonrpc.ParseUnit(spending) if err != nil { return fmt.Errorf("Wrong value in --amount flag: %v", err.Error()) } diff --git a/cmd/aergocli/cmd/receipt.go b/cmd/aergocli/cmd/receipt.go index fc7d8fefe..b7c8d3b62 100644 --- a/cmd/aergocli/cmd/receipt.go +++ b/cmd/aergocli/cmd/receipt.go @@ -9,8 +9,8 @@ import ( "context" "log" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -36,7 +36,7 @@ func init() { if err != nil { log.Fatal(err) } - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) }, }, ) diff --git a/cmd/aergocli/cmd/root.go b/cmd/aergocli/cmd/root.go index 53d496d95..8c025feef 100644 --- a/cmd/aergocli/cmd/root.go +++ b/cmd/aergocli/cmd/root.go @@ -9,12 +9,11 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "log" "os" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/rs/zerolog" "github.com/spf13/cobra" "google.golang.org/grpc" @@ -143,7 +142,7 @@ func connectAergo(cmd *cobra.Command, args []string) { log.Fatal("wrong tls setting : ", err) } certPool := x509.NewCertPool() - ca, err := ioutil.ReadFile(rootConfig.TLS.CACert) + ca, err := os.ReadFile(rootConfig.TLS.CACert) if err != nil { log.Fatal("could not read server certification file : ", err) } @@ -160,7 +159,7 @@ func connectAergo(cmd *cobra.Command, args []string) { opts = append(opts, grpc.WithInsecure()) } var ok bool - client, ok = util.GetClient(serverAddr, opts).(*util.ConnClient) + client, ok = jsonrpc.GetClient(serverAddr, opts).(*jsonrpc.ConnClient) if !ok { log.Fatal("internal error. wrong RPC client type") } diff --git a/cmd/aergocli/cmd/root_test.go b/cmd/aergocli/cmd/root_test.go index 1e4af6798..46c39d164 100644 --- a/cmd/aergocli/cmd/root_test.go +++ b/cmd/aergocli/cmd/root_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/aergoio/aergo/v2/cmd/aergocli/cmd/mock_types" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/golang/mock/gomock" "github.com/spf13/cobra" ) @@ -14,7 +14,7 @@ func initMock(t *testing.T) *mock_types.MockAergoRPCServiceClient { test = true ctrl := gomock.NewController(t) mock := mock_types.NewMockAergoRPCServiceClient(ctrl) - mockClient := &util.ConnClient{ + mockClient := &jsonrpc.ConnClient{ AergoRPCServiceClient: mock, } client = mockClient diff --git a/cmd/aergocli/cmd/sendtx.go b/cmd/aergocli/cmd/sendtx.go index f76923ba7..16cda8bde 100644 --- a/cmd/aergocli/cmd/sendtx.go +++ b/cmd/aergocli/cmd/sendtx.go @@ -9,8 +9,8 @@ import ( "context" "errors" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58" "github.com/spf13/cobra" ) @@ -46,7 +46,7 @@ func execSendTX(cmd *cobra.Command, args []string) error { if err != nil { return errors.New("Wrong address in --to flag\n" + err.Error()) } - amountBigInt, err := util.ParseUnit(amount) + amountBigInt, err := jsonrpc.ParseUnit(amount) if err != nil { return errors.New("Wrong value in --amount flag\n" + err.Error()) } @@ -100,12 +100,12 @@ func sendTX(cmd *cobra.Command, tx *types.Tx, account []byte) string { if err != nil { return "Failed request to aergo server: " + err.Error() } - return util.JSON(msgs.Results[0]) + return jsonrpc.JSON(msgs.Results[0]) } else { msg, err := client.SendTX(context.Background(), tx) if err != nil { return "Failed request to aergo sever: " + err.Error() } - return util.JSON(msg) + return jsonrpc.JSON(msg) } } diff --git a/cmd/aergocli/cmd/sendtx_test.go b/cmd/aergocli/cmd/sendtx_test.go index 5cb101dac..1e0a7bb39 100644 --- a/cmd/aergocli/cmd/sendtx_test.go +++ b/cmd/aergocli/cmd/sendtx_test.go @@ -3,8 +3,8 @@ package cmd import ( "testing" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/golang/mock/gomock" "github.com/mr-tron/base58/base58" "github.com/stretchr/testify/assert" diff --git a/cmd/aergocli/cmd/signtx.go b/cmd/aergocli/cmd/signtx.go index d4e8b48db..59b535825 100644 --- a/cmd/aergocli/cmd/signtx.go +++ b/cmd/aergocli/cmd/signtx.go @@ -7,8 +7,8 @@ import ( "github.com/aergoio/aergo/v2/account/key" crypto "github.com/aergoio/aergo/v2/account/key/crypto" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/btcsuite/btcd/btcec" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" @@ -36,7 +36,7 @@ var signCmd = &cobra.Command{ cmd.Printf("need to transaction json input") return } - param, err := util.ParseBase58TxBody([]byte(jsonTx)) + param, err := jsonrpc.ParseBase58TxBody([]byte(jsonTx)) if err != nil { cmd.Printf("Failed: %s\n", err.Error()) return @@ -89,7 +89,7 @@ var signCmd = &cobra.Command{ } if nil == err && msg != nil { - cmd.Println(util.TxConvBase58Addr(msg)) + cmd.Println(jsonrpc.TxConvBase58Addr(msg)) } else { cmd.Printf("Failed: %s\n", err.Error()) } @@ -105,7 +105,7 @@ var verifyCmd = &cobra.Command{ cmd.Printf("need to transaction json input") return } - param, err := util.ParseBase58Tx([]byte(jsonTx)) + param, err := jsonrpc.ParseBase58Tx([]byte(jsonTx)) if err != nil { cmd.Printf("Failed: %s\n", err.Error()) return @@ -117,7 +117,7 @@ var verifyCmd = &cobra.Command{ return } if msg.Tx != nil { - cmd.Println(util.TxConvBase58Addr(msg.Tx)) + cmd.Println(jsonrpc.TxConvBase58Addr(msg.Tx)) } else { cmd.Println(msg.Error) } @@ -127,7 +127,7 @@ var verifyCmd = &cobra.Command{ cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(util.TxConvBase58Addr(param[0])) + cmd.Println(jsonrpc.TxConvBase58Addr(param[0])) } }, } diff --git a/cmd/aergocli/cmd/signtx_test.go b/cmd/aergocli/cmd/signtx_test.go index e76a37b52..35465ed9e 100644 --- a/cmd/aergocli/cmd/signtx_test.go +++ b/cmd/aergocli/cmd/signtx_test.go @@ -6,9 +6,9 @@ import ( "strings" "testing" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/mr-tron/base58/base58" "github.com/stretchr/testify/assert" ) @@ -26,7 +26,7 @@ func TestSignWithKey(t *testing.T) { assert.Equalf(t, types.AddressLength, len(addr), "wrong address length value = %s", output) ouputjson := strings.Join(outputline[1:], "") - var tx util.InOutTx + var tx jsonrpc.InOutTx err = json.Unmarshal([]byte(ouputjson), &tx) assert.NoError(t, err, "should be success") diff --git a/cmd/aergocli/cmd/stake.go b/cmd/aergocli/cmd/stake.go index b4bc18038..0f843ef0a 100644 --- a/cmd/aergocli/cmd/stake.go +++ b/cmd/aergocli/cmd/stake.go @@ -9,8 +9,8 @@ import ( "encoding/json" "errors" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -47,7 +47,7 @@ func sendStake(cmd *cobra.Command, s bool) error { } else { ci.Name = types.Opunstake.Cmd() } - amountBigInt, err := util.ParseUnit(amount) + amountBigInt, err := jsonrpc.ParseUnit(amount) if err != nil { return errors.New("Failed to parse --amount flag\n" + err.Error()) } diff --git a/cmd/aergocli/cmd/vote.go b/cmd/aergocli/cmd/vote.go index 880980b9c..00dc966e6 100644 --- a/cmd/aergocli/cmd/vote.go +++ b/cmd/aergocli/cmd/vote.go @@ -12,8 +12,8 @@ import ( "os" "strings" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -136,7 +136,7 @@ func execVoteStat(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) return } else if fflags.Changed("id") == true { msg, err := client.GetVotes(context.Background(), &types.VoteParams{ diff --git a/cmd/colaris/cmd/blacklist.go b/cmd/colaris/cmd/blacklist.go index 3452ea547..b0acca4f2 100644 --- a/cmd/colaris/cmd/blacklist.go +++ b/cmd/colaris/cmd/blacklist.go @@ -9,8 +9,8 @@ import ( "context" "strconv" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -65,7 +65,7 @@ func listBlacklistEntries(cmd *cobra.Command, args []string) { return } - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) } func addBlacklistEntry(cmd *cobra.Command, args []string) { diff --git a/cmd/colaris/cmd/common.go b/cmd/colaris/cmd/common.go index 848e30338..16697c870 100644 --- a/cmd/colaris/cmd/common.go +++ b/cmd/colaris/cmd/common.go @@ -8,8 +8,8 @@ package cmd import ( "fmt" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/golang/protobuf/proto" "google.golang.org/grpc" ) diff --git a/cmd/colaris/cmd/current.go b/cmd/colaris/cmd/current.go index 4d971f197..7dec1b6e1 100644 --- a/cmd/colaris/cmd/current.go +++ b/cmd/colaris/cmd/current.go @@ -9,11 +9,9 @@ import ( "context" "time" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" - - "github.com/mr-tron/base58/base58" - "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" + "github.com/mr-tron/base58/base58" "github.com/spf13/cobra" ) @@ -63,7 +61,7 @@ func execCurrentPeers(cmd *cobra.Command, args []string) { for i, p := range msg.Peers { ppList[i] = NewJSONPolarisPeer(p) } - cmd.Println(util.B58JSON(ppList)) + cmd.Println(jsonrpc.B58JSON(ppList)) } type PolarisPeerAlias types.PolarisPeer diff --git a/cmd/colaris/cmd/metric.go b/cmd/colaris/cmd/metric.go index 9b6e2145b..cca89d40e 100644 --- a/cmd/colaris/cmd/metric.go +++ b/cmd/colaris/cmd/metric.go @@ -8,8 +8,8 @@ package cmd import ( "context" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) @@ -34,5 +34,5 @@ func execMetric(cmd *cobra.Command, args []string) { return } // address and peerid should be encoded, respectively - cmd.Println(util.JSON(msg)) + cmd.Println(jsonrpc.JSON(msg)) } diff --git a/consensus/impl/raftv2/cluster.go b/consensus/impl/raftv2/cluster.go index 2cf27b7cb..6b972eeda 100644 --- a/consensus/impl/raftv2/cluster.go +++ b/consensus/impl/raftv2/cluster.go @@ -12,12 +12,12 @@ import ( "sync" "time" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/consensus" "github.com/aergoio/aergo/v2/internal/enc" "github.com/aergoio/aergo/v2/message" "github.com/aergoio/aergo/v2/pkg/component" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" raftlib "github.com/aergoio/etcd/raft" "github.com/aergoio/etcd/raft/raftpb" ) @@ -1010,7 +1010,7 @@ func (cl *Cluster) AfterConfChange(cc *raftpb.ConfChange, member *consensus.Memb propose := cl.savedChange - logger.Info().Str("req", util.JSON(propose.Cc)).Msg("conf change succeed") + logger.Info().Str("req", jsonrpc.JSON(propose.Cc)).Msg("conf change succeed") cl.resetSavedConfChangePropose() diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index 9b0675a12..aa9acc5a8 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -14,9 +14,9 @@ import ( "time" crypto "github.com/aergoio/aergo/v2/account/key/crypto" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/config" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/btcsuite/btcd/btcec" "github.com/stretchr/testify/assert" ) diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index 48f7d3ef5..b67e6d3c5 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -7,16 +7,16 @@ import ( "encoding/binary" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strconv" "strings" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/internal/common" "github.com/aergoio/aergo/v2/rpc" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/asaskevich/govalidator" "github.com/mr-tron/base58" ) @@ -166,7 +166,7 @@ func (api *Web3APIv1) GetState() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - balance, err := util.ConvertUnit(msg.GetBalanceBigInt(), "aergo") + balance, err := jsonrpc.ConvertUnit(msg.GetBalanceBigInt(), "aergo") if err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -208,7 +208,7 @@ func (api *Web3APIv1) GetStateAndProof() (handler http.Handler, ok bool) { if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - balance, err := util.ConvertUnit(msg.GetState().GetBalanceBigInt(), "aergo") + balance, err := jsonrpc.ConvertUnit(msg.GetState().GetBalanceBigInt(), "aergo") if err != nil { return commonResponseHandler(&types.Empty{}, err), true } @@ -323,7 +323,7 @@ func (api *Web3APIv1) GetBlock() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetBlockTransactionCount() (handler http.Handler, ok bool) { @@ -400,7 +400,7 @@ func (api *Web3APIv1) Blockchain() (handler http.Handler, ok bool) { ChainInfo: chainInfo, } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { @@ -463,7 +463,7 @@ func (api *Web3APIv1) GetBlockBody() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { @@ -520,7 +520,7 @@ func (api *Web3APIv1) ListBlockHeaders() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { @@ -562,7 +562,7 @@ func (api *Web3APIv1) GetBlockMetadata() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) ListBlockMetadata() (handler http.Handler, ok bool) { @@ -707,14 +707,14 @@ func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { msg, err := api.rpc.GetTX(api.request.Context(), request) if err == nil { - return commonResponseHandler(util.ConvTxEx(msg, util.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxEx(msg, jsonrpc.Base58), nil), true } else { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(util.ConvTxInBlockEx(msgblock, util.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxInBlockEx(msgblock, jsonrpc.Base58), nil), true } } @@ -741,14 +741,14 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { msg, err := api.rpc.GetTX(api.request.Context(), request) if err == nil { - return commonResponseHandler(util.ConvTxEx(msg, util.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxEx(msg, jsonrpc.Base58), nil), true } else { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(util.ConvTxInBlockEx(msgblock, util.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxInBlockEx(msgblock, jsonrpc.Base58), nil), true } } @@ -966,7 +966,7 @@ func (api *Web3APIv1) QueryContractState() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) NodeState() (handler http.Handler, ok bool) { @@ -1036,7 +1036,7 @@ func (api *Web3APIv1) GetPeers() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { @@ -1060,7 +1060,7 @@ func (api *Web3APIv1) GetServerInfo() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetStaking() (handler http.Handler, ok bool) { @@ -1150,7 +1150,7 @@ func (api *Web3APIv1) Metric() (handler http.Handler, ok bool) { return commonResponseHandler(&types.Empty{}, err), true } - return stringResponseHandler(util.JSON(result), nil), true + return stringResponseHandler(jsonrpc.JSON(result), nil), true } func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { @@ -1188,7 +1188,7 @@ func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { out.On = &msg.On } - return stringResponseHandler(util.B58JSON(out), nil), true + return stringResponseHandler(jsonrpc.B58JSON(out), nil), true } func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { @@ -1223,12 +1223,12 @@ func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { } func (api *Web3APIv1) CommitTX() (handler http.Handler, ok bool) { - body, err := ioutil.ReadAll(api.request.Body) + body, err := io.ReadAll(api.request.Body) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - txs, err := util.ParseBase58Tx([]byte(body)) + txs, err := jsonrpc.ParseBase58Tx([]byte(body)) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index d47d42b2a..cd170528f 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -3,14 +3,13 @@ package web3 import ( "encoding/json" "fmt" - "io/ioutil" "net/http" + "os" "strconv" "github.com/aergoio/aergo-lib/log" - "github.com/aergoio/aergo/v2/rpc" - "github.com/aergoio/aergo/v2/config" + "github.com/aergoio/aergo/v2/rpc" "github.com/didip/tollbooth" "github.com/rs/cors" ) @@ -62,7 +61,7 @@ func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { } func serveSwaggerYAML(w http.ResponseWriter, r *http.Request) { - yamlContent, err := ioutil.ReadFile("./swagger/swagger.yaml") + yamlContent, err := os.ReadFile("./swagger/swagger.yaml") if err != nil { http.Error(w, "Failed to read YAML file", http.StatusInternalServerError) return @@ -73,7 +72,7 @@ func serveSwaggerYAML(w http.ResponseWriter, r *http.Request) { } func serveSwaggerUI(w http.ResponseWriter, r *http.Request) { - htmlContent, err := ioutil.ReadFile("./swagger/swagger-ui.html") + htmlContent, err := os.ReadFile("./swagger/swagger-ui.html") if err != nil { http.Error(w, "Failed to read HTML file", http.StatusInternalServerError) return diff --git a/tools/mpdumpdiag/main.go b/tools/mpdumpdiag/main.go index 14f98adc8..5a5c3af90 100644 --- a/tools/mpdumpdiag/main.go +++ b/tools/mpdumpdiag/main.go @@ -5,11 +5,10 @@ import ( "encoding/binary" "encoding/json" "io" - "io/ioutil" "os" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/golang/protobuf/proto" "github.com/spf13/cobra" ) @@ -53,7 +52,7 @@ func runPrintCmd(cmd *cobra.Command, args []string) { reader := bufio.NewReader(file) var count int - var out []*util.InOutTx + var out []*jsonrpc.InOutTx for { buf := types.Tx{} byteInt := make([]byte, 4) @@ -83,7 +82,7 @@ func runPrintCmd(cmd *cobra.Command, args []string) { count++ //mp.put(types.NewTransaction(&buf)) // nolint: errcheck - out = append(out, util.ConvTx(types.NewTransaction(&buf).GetTx())) + out = append(out, jsonrpc.ConvTx(types.NewTransaction(&buf).GetTx())) } b, e := json.MarshalIndent(out, "", " ") if e == nil { @@ -105,11 +104,11 @@ func runGenCmd(cmd *cobra.Command, args []string) { writer := bufio.NewWriter(file) defer writer.Flush() //nolint: errcheck - b, err := ioutil.ReadFile(args[0]) + b, err := os.ReadFile(args[0]) if err != nil { cmd.Println("error: failed to read source file", err.Error()) } - txlist, err := util.ParseBase58Tx(b) + txlist, err := jsonrpc.ParseBase58Tx(b) for _, v := range txlist { var total_data []byte data, err := proto.Marshal(v) diff --git a/cmd/aergocli/util/base58addr.go b/types/jsonrpc/base58addr.go similarity index 99% rename from cmd/aergocli/util/base58addr.go rename to types/jsonrpc/base58addr.go index 90993c03a..283c46dee 100644 --- a/cmd/aergocli/util/base58addr.go +++ b/types/jsonrpc/base58addr.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "encoding/json" diff --git a/cmd/aergocli/util/base58addr_test.go b/types/jsonrpc/base58addr_test.go similarity index 99% rename from cmd/aergocli/util/base58addr_test.go rename to types/jsonrpc/base58addr_test.go index a3f962b98..a7f714388 100644 --- a/cmd/aergocli/util/base58addr_test.go +++ b/types/jsonrpc/base58addr_test.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "testing" diff --git a/cmd/aergocli/util/base64ToHex.go b/types/jsonrpc/base64ToHex.go similarity index 97% rename from cmd/aergocli/util/base64ToHex.go rename to types/jsonrpc/base64ToHex.go index 0df49c088..ca4df2a03 100644 --- a/cmd/aergocli/util/base64ToHex.go +++ b/types/jsonrpc/base64ToHex.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "encoding/hex" diff --git a/cmd/aergocli/util/convChaininfo.go b/types/jsonrpc/convChaininfo.go similarity index 99% rename from cmd/aergocli/util/convChaininfo.go rename to types/jsonrpc/convChaininfo.go index 0efa70662..036f75dee 100644 --- a/cmd/aergocli/util/convChaininfo.go +++ b/types/jsonrpc/convChaininfo.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "encoding/json" diff --git a/cmd/aergocli/util/convTx.go b/types/jsonrpc/convTx.go similarity index 99% rename from cmd/aergocli/util/convTx.go rename to types/jsonrpc/convTx.go index a3392d258..ce7e6c6f6 100644 --- a/cmd/aergocli/util/convTx.go +++ b/types/jsonrpc/convTx.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import "github.com/aergoio/aergo/v2/types" diff --git a/cmd/aergocli/util/convTx_test.go b/types/jsonrpc/convTx_test.go similarity index 97% rename from cmd/aergocli/util/convTx_test.go rename to types/jsonrpc/convTx_test.go index 536c9950c..ba4f70cb5 100644 --- a/cmd/aergocli/util/convTx_test.go +++ b/types/jsonrpc/convTx_test.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "testing" diff --git a/cmd/aergocli/util/encoding/encoding.go b/types/jsonrpc/encoding/encoding.go similarity index 100% rename from cmd/aergocli/util/encoding/encoding.go rename to types/jsonrpc/encoding/encoding.go diff --git a/cmd/aergocli/util/encoding/json/decode.go b/types/jsonrpc/encoding/json/decode.go similarity index 100% rename from cmd/aergocli/util/encoding/json/decode.go rename to types/jsonrpc/encoding/json/decode.go diff --git a/cmd/aergocli/util/encoding/json/decode_test.go b/types/jsonrpc/encoding/json/decode_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/decode_test.go rename to types/jsonrpc/encoding/json/decode_test.go diff --git a/cmd/aergocli/util/encoding/json/encode.go b/types/jsonrpc/encoding/json/encode.go similarity index 100% rename from cmd/aergocli/util/encoding/json/encode.go rename to types/jsonrpc/encoding/json/encode.go diff --git a/cmd/aergocli/util/encoding/json/encode_test.go b/types/jsonrpc/encoding/json/encode_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/encode_test.go rename to types/jsonrpc/encoding/json/encode_test.go diff --git a/cmd/aergocli/util/encoding/json/example_marshaling_test.go b/types/jsonrpc/encoding/json/example_marshaling_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/example_marshaling_test.go rename to types/jsonrpc/encoding/json/example_marshaling_test.go diff --git a/cmd/aergocli/util/encoding/json/example_test.go b/types/jsonrpc/encoding/json/example_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/example_test.go rename to types/jsonrpc/encoding/json/example_test.go diff --git a/cmd/aergocli/util/encoding/json/fold.go b/types/jsonrpc/encoding/json/fold.go similarity index 100% rename from cmd/aergocli/util/encoding/json/fold.go rename to types/jsonrpc/encoding/json/fold.go diff --git a/cmd/aergocli/util/encoding/json/fold_test.go b/types/jsonrpc/encoding/json/fold_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/fold_test.go rename to types/jsonrpc/encoding/json/fold_test.go diff --git a/cmd/aergocli/util/encoding/json/indent.go b/types/jsonrpc/encoding/json/indent.go similarity index 100% rename from cmd/aergocli/util/encoding/json/indent.go rename to types/jsonrpc/encoding/json/indent.go diff --git a/cmd/aergocli/util/encoding/json/number_test.go b/types/jsonrpc/encoding/json/number_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/number_test.go rename to types/jsonrpc/encoding/json/number_test.go diff --git a/cmd/aergocli/util/encoding/json/scanner.go b/types/jsonrpc/encoding/json/scanner.go similarity index 100% rename from cmd/aergocli/util/encoding/json/scanner.go rename to types/jsonrpc/encoding/json/scanner.go diff --git a/cmd/aergocli/util/encoding/json/scanner_test.go b/types/jsonrpc/encoding/json/scanner_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/scanner_test.go rename to types/jsonrpc/encoding/json/scanner_test.go diff --git a/cmd/aergocli/util/encoding/json/stream.go b/types/jsonrpc/encoding/json/stream.go similarity index 100% rename from cmd/aergocli/util/encoding/json/stream.go rename to types/jsonrpc/encoding/json/stream.go diff --git a/cmd/aergocli/util/encoding/json/stream_test.go b/types/jsonrpc/encoding/json/stream_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/stream_test.go rename to types/jsonrpc/encoding/json/stream_test.go diff --git a/cmd/aergocli/util/encoding/json/tables.go b/types/jsonrpc/encoding/json/tables.go similarity index 100% rename from cmd/aergocli/util/encoding/json/tables.go rename to types/jsonrpc/encoding/json/tables.go diff --git a/cmd/aergocli/util/encoding/json/tagkey_test.go b/types/jsonrpc/encoding/json/tagkey_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/tagkey_test.go rename to types/jsonrpc/encoding/json/tagkey_test.go diff --git a/cmd/aergocli/util/encoding/json/tags.go b/types/jsonrpc/encoding/json/tags.go similarity index 100% rename from cmd/aergocli/util/encoding/json/tags.go rename to types/jsonrpc/encoding/json/tags.go diff --git a/cmd/aergocli/util/encoding/json/tags_test.go b/types/jsonrpc/encoding/json/tags_test.go similarity index 100% rename from cmd/aergocli/util/encoding/json/tags_test.go rename to types/jsonrpc/encoding/json/tags_test.go diff --git a/cmd/aergocli/util/encoding/json/testdata/code.json.gz b/types/jsonrpc/encoding/json/testdata/code.json.gz similarity index 100% rename from cmd/aergocli/util/encoding/json/testdata/code.json.gz rename to types/jsonrpc/encoding/json/testdata/code.json.gz diff --git a/cmd/aergocli/util/grpccommon.go b/types/jsonrpc/grpccommon.go similarity index 94% rename from cmd/aergocli/util/grpccommon.go rename to types/jsonrpc/grpccommon.go index e21af7fba..e75010a3b 100644 --- a/cmd/aergocli/util/grpccommon.go +++ b/types/jsonrpc/grpccommon.go @@ -3,13 +3,13 @@ * @copyright defined in aergo/LICENSE.txt */ -package util +package jsonrpc import ( "fmt" - "github.com/aergoio/aergo/v2/cmd/aergocli/util/encoding/json" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" protobuf "github.com/golang/protobuf/proto" "google.golang.org/grpc" ) diff --git a/cmd/aergocli/util/unit.go b/types/jsonrpc/unit.go similarity index 99% rename from cmd/aergocli/util/unit.go rename to types/jsonrpc/unit.go index 2905ad6b7..d56058f84 100644 --- a/cmd/aergocli/util/unit.go +++ b/types/jsonrpc/unit.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "fmt" diff --git a/cmd/aergocli/util/unit_test.go b/types/jsonrpc/unit_test.go similarity index 99% rename from cmd/aergocli/util/unit_test.go rename to types/jsonrpc/unit_test.go index 42bcb5b99..219c3188e 100644 --- a/cmd/aergocli/util/unit_test.go +++ b/types/jsonrpc/unit_test.go @@ -1,4 +1,4 @@ -package util +package jsonrpc import ( "math/big" From 433e3e45fba8c2aca47b26290c0e9ab103c7504b Mon Sep 17 00:00:00 2001 From: jinuk Date: Tue, 7 Nov 2023 08:50:39 +0900 Subject: [PATCH 016/134] aergosvr make web3 --- cmd/aergosvr/aergosvr.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/aergosvr/aergosvr.go b/cmd/aergosvr/aergosvr.go index 1ede78845..072aa7782 100644 --- a/cmd/aergosvr/aergosvr.go +++ b/cmd/aergosvr/aergosvr.go @@ -23,6 +23,7 @@ import ( "github.com/aergoio/aergo/v2/pkg/component" polarisclient "github.com/aergoio/aergo/v2/polaris/client" "github.com/aergoio/aergo/v2/rpc" + "github.com/aergoio/aergo/v2/rpc/web3" "github.com/aergoio/aergo/v2/syncer" "github.com/spf13/cobra" ) @@ -123,6 +124,7 @@ func rootRun(cmd *cobra.Command, args []string) { syncSvc := syncer.NewSyncer(cfg, chainSvc, nil) p2pSvc := p2p.NewP2P(cfg, chainSvc) pmapSvc := polarisclient.NewPolarisConnectSvc(cfg.P2P, p2pSvc) + web3.NewWeb3(cfg, rpcSvc.GetActualServer()) var accountSvc component.IComponent if cfg.Personal { From a3ffff7ee18509609e5235d0847e3e6d952d67ae Mon Sep 17 00:00:00 2001 From: jinuk Date: Fri, 10 Nov 2023 14:00:22 +0900 Subject: [PATCH 017/134] Change swagger location --- {swagger => rpc/swagger}/swagger-ui.html | 0 {swagger => rpc/swagger}/swagger.yaml | 51 +++++++++--------------- rpc/web3/web3.go | 4 +- 3 files changed, 21 insertions(+), 34 deletions(-) rename {swagger => rpc/swagger}/swagger-ui.html (100%) rename {swagger => rpc/swagger}/swagger.yaml (97%) diff --git a/swagger/swagger-ui.html b/rpc/swagger/swagger-ui.html similarity index 100% rename from swagger/swagger-ui.html rename to rpc/swagger/swagger-ui.html diff --git a/swagger/swagger.yaml b/rpc/swagger/swagger.yaml similarity index 97% rename from swagger/swagger.yaml rename to rpc/swagger/swagger.yaml index 73bb384c3..57097e040 100644 --- a/swagger/swagger.yaml +++ b/rpc/swagger/swagger.yaml @@ -437,38 +437,25 @@ paths: schema: type: object properties: - signedTransaction: - type: string - hash: - type: string - nonce: - type: integer - account: - type: string - recipient: - type: string - amount: - type: string - payload: - type: string - gasLimit: - type: integer - gasPrice: - type: string - type: - type: string - enum: - - "NORMAL" - - "GOVERNANCE" - - "REDEPLOY" - - "FEEDELEGATION" - - "TRANSFER" - - "CALL" - - "DEPLOY" - chainIdHash: - type: string - sign: + Hash: type: string + Body: + type: object + properties: + Nonce: + type: integer + Account: + type: string + Recipient: + type: string + Amount: + type: string + ChainIdHash: + type: string + Sign: + type: string + Type: + type: integer responses: "200": description: Successful response @@ -502,7 +489,7 @@ paths: in: query schema: type: string - example: { "key": "name" } + example: '[{ "key": "name" }]' responses: "200": description: Successful response diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index cd170528f..133ffb022 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -61,7 +61,7 @@ func NewWeb3(cfg *config.Config, rpc *rpc.AergoRPCService) { } func serveSwaggerYAML(w http.ResponseWriter, r *http.Request) { - yamlContent, err := os.ReadFile("./swagger/swagger.yaml") + yamlContent, err := os.ReadFile("./rpc/swagger/swagger.yaml") if err != nil { http.Error(w, "Failed to read YAML file", http.StatusInternalServerError) return @@ -72,7 +72,7 @@ func serveSwaggerYAML(w http.ResponseWriter, r *http.Request) { } func serveSwaggerUI(w http.ResponseWriter, r *http.Request) { - htmlContent, err := os.ReadFile("./swagger/swagger-ui.html") + htmlContent, err := os.ReadFile("./rpc/swagger/swagger-ui.html") if err != nil { http.Error(w, "Failed to read HTML file", http.StatusInternalServerError) return From 1a859ab7b9f6c29691fb42ad8f56acf623364bb8 Mon Sep 17 00:00:00 2001 From: kch Date: Wed, 15 Nov 2023 04:09:28 +0000 Subject: [PATCH 018/134] fix conflict --- cmd/aergocli/cmd/getblock.go | 2 +- go.mod | 7 +++---- rpc/web3/web3.go | 4 +--- tools/mpdumpdiag/main.go | 2 +- types/jsonrpc/types.go | 1 + 5 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 types/jsonrpc/types.go diff --git a/cmd/aergocli/cmd/getblock.go b/cmd/aergocli/cmd/getblock.go index abb9f2a42..1e5ed3653 100644 --- a/cmd/aergocli/cmd/getblock.go +++ b/cmd/aergocli/cmd/getblock.go @@ -11,9 +11,9 @@ import ( "errors" "fmt" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/internal/enc/base58" aergorpc "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) diff --git a/go.mod b/go.mod index ba8a2b44a..9a854d145 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ require ( github.com/aergoio/aergo-lib v1.1.0 github.com/aergoio/etcd v0.0.0-20190429013412-e8b3f96f6399 github.com/anaskhan96/base58check v0.0.0-20181220122047-b05365d494c4 + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/bluele/gcache v0.0.0-20190518031135-bc40bd653833 github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 github.com/c-bata/go-prompt v0.2.3 github.com/coreos/go-semver v0.3.0 github.com/davecgh/go-spew v1.1.1 github.com/derekparker/trie v0.0.0-20190322172448-1ce4922c7ad9 + github.com/didip/tollbooth v4.0.2+incompatible github.com/emirpasic/gods v1.12.0 github.com/fsnotify/fsnotify v1.4.8-0.20180830220226-ccc981bf8038 github.com/funkygao/golib v0.0.0-20180314131852-90d4905c1961 @@ -35,6 +37,7 @@ require ( github.com/multiformats/go-multiaddr-net v0.1.0 github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.9.1 + github.com/rs/cors v1.7.0 github.com/rs/zerolog v1.29.1 github.com/sanity-io/litter v1.5.5 github.com/soheilhy/cmux v0.1.4 @@ -51,8 +54,6 @@ require ( github.com/Workiva/go-datastructures v1.0.50 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.1.1 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/beorn7/perks v1.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect @@ -60,7 +61,6 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v3 v3.2103.2 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect - github.com/didip/tollbooth v4.0.2+incompatible // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/funkygao/assert v0.0.0-20160929004900-4a267e33bc79 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -132,7 +132,6 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.15.0 // indirect github.com/prometheus/procfs v0.3.0 // indirect - github.com/rs/cors v1.7.0 // indirect github.com/serialx/hashring v0.0.0-20190515033939-7706f26af194 // indirect github.com/smola/gocompat v0.2.0 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect diff --git a/rpc/web3/web3.go b/rpc/web3/web3.go index 133ffb022..33b76702c 100644 --- a/rpc/web3/web3.go +++ b/rpc/web3/web3.go @@ -14,9 +14,7 @@ import ( "github.com/rs/cors" ) -type RestAPI struct { - rpc *rpc.AergoRPCService - request *http.Request +type Web3 struct { } var ( diff --git a/tools/mpdumpdiag/main.go b/tools/mpdumpdiag/main.go index d676182ea..c869e4afd 100644 --- a/tools/mpdumpdiag/main.go +++ b/tools/mpdumpdiag/main.go @@ -7,9 +7,9 @@ import ( "io" "os" - "github.com/aergoio/aergo/v2/cmd/aergocli/util" "github.com/aergoio/aergo/v2/internal/enc/proto" "github.com/aergoio/aergo/v2/types" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" ) diff --git a/types/jsonrpc/types.go b/types/jsonrpc/types.go new file mode 100644 index 000000000..29a4d6aba --- /dev/null +++ b/types/jsonrpc/types.go @@ -0,0 +1 @@ +package jsonrpc From 469b4dfa2a63031a8df1fbc60b62b64ae50b51d2 Mon Sep 17 00:00:00 2001 From: kch Date: Wed, 15 Nov 2023 05:19:56 +0000 Subject: [PATCH 019/134] fix conflict --- rpc/web3/v1.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index b67e6d3c5..04c4f25c0 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -3,7 +3,6 @@ package web3 import ( "bytes" "crypto/sha256" - "encoding/base64" "encoding/binary" "encoding/json" "fmt" @@ -14,11 +13,12 @@ import ( "strings" "github.com/aergoio/aergo/v2/internal/common" + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/internal/enc/base64" "github.com/aergoio/aergo/v2/rpc" "github.com/aergoio/aergo/v2/types" "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/asaskevich/govalidator" - "github.com/mr-tron/base58" ) type Web3APIv1 struct { @@ -1200,7 +1200,7 @@ func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { request := &types.SingleBytes{} hash := values.Get("hash") if hash != "" { - hashBytes, err := base64.StdEncoding.DecodeString(hash) + hashBytes, err := base64.Decode(hash) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } From f482a921e91df0f90bf914e7c8da61f1ace043e0 Mon Sep 17 00:00:00 2001 From: kch Date: Thu, 16 Nov 2023 07:54:43 +0000 Subject: [PATCH 020/134] move grpc client to cmd --- .../aergocli/cmd/client.go | 23 +--------------- cmd/aergocli/cmd/contract.go | 2 +- cmd/aergocli/cmd/mempool.go | 3 +-- cmd/aergocli/cmd/root.go | 3 +-- cmd/aergocli/cmd/root_test.go | 3 +-- types/jsonrpc/json.go | 27 +++++++++++++++++++ types/jsonrpc/types.go | 1 - 7 files changed, 32 insertions(+), 30 deletions(-) rename types/jsonrpc/grpccommon.go => cmd/aergocli/cmd/client.go (57%) create mode 100644 types/jsonrpc/json.go delete mode 100644 types/jsonrpc/types.go diff --git a/types/jsonrpc/grpccommon.go b/cmd/aergocli/cmd/client.go similarity index 57% rename from types/jsonrpc/grpccommon.go rename to cmd/aergocli/cmd/client.go index e75010a3b..52d90ed76 100644 --- a/types/jsonrpc/grpccommon.go +++ b/cmd/aergocli/cmd/client.go @@ -3,14 +3,12 @@ * @copyright defined in aergo/LICENSE.txt */ -package jsonrpc +package cmd import ( "fmt" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" - protobuf "github.com/golang/protobuf/proto" "google.golang.org/grpc" ) @@ -42,22 +40,3 @@ func (c *ConnClient) Close() { c.conn.Close() c.conn = nil } - -// JSON converts protobuf message(struct) to json notation -func JSON(pb protobuf.Message) string { - jsonout, err := json.MarshalIndent(pb, "", " ") - if err != nil { - fmt.Printf("Failed: %s\n", err.Error()) - return "" - } - return string(jsonout) -} - -func B58JSON(i interface{}) string { - jsonout, err := json.MarshalIndent(i, "", " ") - if err != nil { - fmt.Printf("Failed: %s\n", err.Error()) - return "" - } - return string(jsonout) -} diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 4374f0e8e..531f5e664 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -21,7 +21,7 @@ import ( ) var ( - client *jsonrpc.ConnClient + client *ConnClient admClient types.AdminRPCServiceClient data string nonce uint64 diff --git a/cmd/aergocli/cmd/mempool.go b/cmd/aergocli/cmd/mempool.go index 0dd9a4b37..96643675d 100644 --- a/cmd/aergocli/cmd/mempool.go +++ b/cmd/aergocli/cmd/mempool.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/spf13/cobra" "google.golang.org/grpc" ) @@ -77,6 +76,6 @@ func newAergoAdminClient(sockPath string) types.AdminRPCServiceClient { grpc.WithInsecure(), } return types.NewAdminRPCServiceClient( - jsonrpc.GetConn(fmt.Sprintf("unix:%s", sockPath), opts), + GetConn(fmt.Sprintf("unix:%s", sockPath), opts), ) } diff --git a/cmd/aergocli/cmd/root.go b/cmd/aergocli/cmd/root.go index 8c025feef..b1e4957a0 100644 --- a/cmd/aergocli/cmd/root.go +++ b/cmd/aergocli/cmd/root.go @@ -13,7 +13,6 @@ import ( "os" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/rs/zerolog" "github.com/spf13/cobra" "google.golang.org/grpc" @@ -159,7 +158,7 @@ func connectAergo(cmd *cobra.Command, args []string) { opts = append(opts, grpc.WithInsecure()) } var ok bool - client, ok = jsonrpc.GetClient(serverAddr, opts).(*jsonrpc.ConnClient) + client, ok = GetClient(serverAddr, opts).(*ConnClient) if !ok { log.Fatal("internal error. wrong RPC client type") } diff --git a/cmd/aergocli/cmd/root_test.go b/cmd/aergocli/cmd/root_test.go index 46c39d164..a372794d1 100644 --- a/cmd/aergocli/cmd/root_test.go +++ b/cmd/aergocli/cmd/root_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/aergoio/aergo/v2/cmd/aergocli/cmd/mock_types" - "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/golang/mock/gomock" "github.com/spf13/cobra" ) @@ -14,7 +13,7 @@ func initMock(t *testing.T) *mock_types.MockAergoRPCServiceClient { test = true ctrl := gomock.NewController(t) mock := mock_types.NewMockAergoRPCServiceClient(ctrl) - mockClient := &jsonrpc.ConnClient{ + mockClient := &ConnClient{ AergoRPCServiceClient: mock, } client = mockClient diff --git a/types/jsonrpc/json.go b/types/jsonrpc/json.go new file mode 100644 index 000000000..4fad6c03c --- /dev/null +++ b/types/jsonrpc/json.go @@ -0,0 +1,27 @@ +package jsonrpc + +import ( + "encoding/json" + "fmt" + + "github.com/aergoio/aergo/v2/internal/enc/proto" +) + +// JSON converts protobuf message(struct) to json notation +func JSON(pb proto.Message) string { + jsonout, err := json.MarshalIndent(pb, "", " ") + if err != nil { + fmt.Printf("Failed: %s\n", err.Error()) + return "" + } + return string(jsonout) +} + +func B58JSON(i interface{}) string { + jsonout, err := json.MarshalIndent(i, "", " ") + if err != nil { + fmt.Printf("Failed: %s\n", err.Error()) + return "" + } + return string(jsonout) +} diff --git a/types/jsonrpc/types.go b/types/jsonrpc/types.go deleted file mode 100644 index 29a4d6aba..000000000 --- a/types/jsonrpc/types.go +++ /dev/null @@ -1 +0,0 @@ -package jsonrpc From 81bc9e048341dc50afbce844220047e5d1c56477 Mon Sep 17 00:00:00 2001 From: kch Date: Thu, 16 Nov 2023 07:57:09 +0000 Subject: [PATCH 021/134] experiment - tidy jsonrpc struct --- types/jsonrpc/base58addr.go | 63 ------------- types/jsonrpc/base64ToHex.go | 9 -- types/jsonrpc/convChaininfo.go | 21 ----- types/jsonrpc/convTx.go | 28 ------ types/jsonrpc/zzz__block.go | 80 ++++++++++++++++ types/jsonrpc/zzz__chainInfo.go | 57 ++++++++++++ types/jsonrpc/zzz__chainstatus.go | 42 +++++++++ types/jsonrpc/zzz__peer.go | 95 +++++++++++++++++++ types/jsonrpc/zzz__tx.go | 146 ++++++++++++++++++++++++++++++ 9 files changed, 420 insertions(+), 121 deletions(-) create mode 100644 types/jsonrpc/zzz__block.go create mode 100644 types/jsonrpc/zzz__chainInfo.go create mode 100644 types/jsonrpc/zzz__chainstatus.go create mode 100644 types/jsonrpc/zzz__peer.go create mode 100644 types/jsonrpc/zzz__tx.go diff --git a/types/jsonrpc/base58addr.go b/types/jsonrpc/base58addr.go index 5804f2255..4f186ff2a 100644 --- a/types/jsonrpc/base58addr.go +++ b/types/jsonrpc/base58addr.go @@ -13,69 +13,6 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutBlockHeader struct { - ChainID string - Version int32 - PrevBlockHash string - BlockNo uint64 - Timestamp int64 - BlockRootHash string - TxRootHash string - ReceiptsRootHash string - Confirms uint64 - PubKey string - Sign string - CoinbaseAccount string - Consensus string -} - -type InOutBlockBody struct { - Txs []*InOutTx -} - -type InOutBlock struct { - Hash string - Header InOutBlockHeader - Body InOutBlockBody -} - -type InOutBlockIdx struct { - BlockHash string - BlockNo uint64 -} - -type InOutPeerAddress struct { - Address string - Port string - PeerId string -} - -type InOutPeer struct { - Role string - Address InOutPeerAddress - BestBlock InOutBlockIdx - LastCheck time.Time - State string - Hidden bool - Self bool - Version string -} - -type LongInOutPeer struct { - InOutPeer - ProducerIDs []string - Certificates []*InOutCert -} - -type InOutCert struct { - CertVersion uint32 - ProducerID string - CreateTime time.Time - ExpireTime time.Time - AgentID string - Addresses []string -} - func FillTxBody(source *InOutTxBody, target *types.TxBody) error { var err error if source == nil { diff --git a/types/jsonrpc/base64ToHex.go b/types/jsonrpc/base64ToHex.go index b0797dcad..a018268bc 100644 --- a/types/jsonrpc/base64ToHex.go +++ b/types/jsonrpc/base64ToHex.go @@ -7,15 +7,6 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutBlockchainStatus struct { - Hash string - Height uint64 - ConsensusInfo *json.RawMessage `json:",omitempty"` - ChainIdHash string - ChainStat *json.RawMessage `json:",omitempty"` - ChainInfo *InOutChainInfo `json:",omitempty"` -} - func ConvHexBlockchainStatus(in *types.BlockchainStatus) string { out := &InOutBlockchainStatus{} out.Hash = hex.Encode(in.BestBlockHash) diff --git a/types/jsonrpc/convChaininfo.go b/types/jsonrpc/convChaininfo.go index 036f75dee..7a76eb614 100644 --- a/types/jsonrpc/convChaininfo.go +++ b/types/jsonrpc/convChaininfo.go @@ -8,27 +8,6 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutChainId struct { - Magic string - Public bool - Mainnet bool - Consensus string - Version int32 -} - -type InOutChainInfo struct { - Chainid InOutChainId - BpNumber uint32 - MaxBlockSize uint64 - MaxTokens string - StakingMinimum string `json:",omitempty"` - StakingTotal string `json:",omitempty"` - GasPrice string `json:",omitempty"` - NamePrice string `json:",omitempty"` - TotalVotingPower string `json:",omitempty"` - VotingReward string `json:",omitempty"` -} - func ConvChainInfoMsg(msg *types.ChainInfo) string { jsonout, err := json.MarshalIndent(convChainInfo(msg), "", " ") if err != nil { diff --git a/types/jsonrpc/convTx.go b/types/jsonrpc/convTx.go index ce7e6c6f6..7b93f804a 100644 --- a/types/jsonrpc/convTx.go +++ b/types/jsonrpc/convTx.go @@ -9,34 +9,6 @@ const ( Base58 ) -type InOutTx struct { - Hash string `json:",omitempty"` - Body *InOutTxBody `json:",omitempty"` -} - -type InOutTxBody struct { - Nonce uint64 `json:",omitempty"` - Account string `json:",omitempty"` - Recipient string `json:",omitempty"` - Amount string `json:",omitempty"` - Payload string `json:",omitempty"` - GasLimit uint64 `json:",omitempty"` - GasPrice string `json:",omitempty"` - Type types.TxType `json:",omitempty"` - ChainIdHash string `json:",omitempty"` - Sign string `json:",omitempty"` -} - -type InOutTxIdx struct { - BlockHash string - Idx int32 -} - -type InOutTxInBlock struct { - TxIdx *InOutTxIdx - Tx *InOutTx -} - func (b *InOutTxBody) String() string { return toString(b) } diff --git a/types/jsonrpc/zzz__block.go b/types/jsonrpc/zzz__block.go new file mode 100644 index 000000000..e007c7530 --- /dev/null +++ b/types/jsonrpc/zzz__block.go @@ -0,0 +1,80 @@ +package jsonrpc + +import ( + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +type InOutBlock struct { + Hash string + Header InOutBlockHeader + Body InOutBlockBody +} + +func (b *InOutBlock) FromProto(msg *types.Block) { + b.Hash = base58.Encode(msg.Hash) + if msg.Header != nil { + b.Header.FromProto(msg.Header) + } + if msg.Body != nil { + b.Body.FromProto(msg.Body) + } +} + +type InOutBlockHeader struct { + ChainID string + Version int32 + PrevBlockHash string + BlockNo uint64 + Timestamp int64 + BlockRootHash string + TxRootHash string + ReceiptsRootHash string + Confirms uint64 + PubKey string + Sign string + CoinbaseAccount string + Consensus string +} + +func (bh *InOutBlockHeader) FromProto(msg *types.BlockHeader) { + bh.ChainID = base58.Encode(msg.GetChainID()) + bh.Version = types.DecodeChainIdVersion(msg.GetChainID()) + bh.PrevBlockHash = base58.Encode(msg.GetPrevBlockHash()) + bh.BlockNo = msg.GetBlockNo() + bh.Timestamp = msg.GetTimestamp() + bh.BlockRootHash = base58.Encode(msg.GetBlocksRootHash()) + bh.TxRootHash = base58.Encode(msg.GetTxsRootHash()) + bh.ReceiptsRootHash = base58.Encode(msg.GetReceiptsRootHash()) + bh.Confirms = msg.GetConfirms() + bh.PubKey = base58.Encode(msg.GetPubKey()) + bh.Sign = base58.Encode(msg.GetSign()) + if msg.GetCoinbaseAccount() != nil { + bh.CoinbaseAccount = types.EncodeAddress(msg.GetCoinbaseAccount()) + } + if consensus := msg.GetConsensus(); consensus != nil { + bh.Consensus = types.EncodeAddress(consensus) + } +} + +type InOutBlockBody struct { + Txs []*InOutTx +} + +func (bb *InOutBlockBody) FromProto(msg *types.BlockBody) { + bb.Txs = make([]*InOutTx, len(msg.Txs)) + for i, tx := range msg.Txs { + bb.Txs[i] = &InOutTx{} + bb.Txs[i].FromProto(tx, Base58) + } +} + +type InOutBlockIdx struct { + BlockHash string + BlockNo uint64 +} + +func (bh *InOutBlockIdx) FromProto(msg *types.NewBlockNotice) { + bh.BlockNo = msg.GetBlockNo() + bh.BlockHash = base58.Encode(msg.GetBlockHash()) +} diff --git a/types/jsonrpc/zzz__chainInfo.go b/types/jsonrpc/zzz__chainInfo.go new file mode 100644 index 000000000..64edee1a1 --- /dev/null +++ b/types/jsonrpc/zzz__chainInfo.go @@ -0,0 +1,57 @@ +package jsonrpc + +import ( + "encoding/json" + "math/big" + + "github.com/aergoio/aergo/v2/consensus" + "github.com/aergoio/aergo/v2/types" +) + +type InOutChainInfo struct { + Chainid InOutChainId + BpNumber uint32 + MaxBlockSize uint64 + MaxTokens string + StakingMinimum string `json:",omitempty"` + StakingTotal string `json:",omitempty"` + GasPrice string `json:",omitempty"` + NamePrice string `json:",omitempty"` + TotalVotingPower string `json:",omitempty"` + VotingReward string `json:",omitempty"` +} + +func (ci *InOutChainInfo) FromProto(msg *types.ChainInfo) { + if msg.Id != nil { + ci.Chainid.FromProto(msg.Id) + } + ci.MaxTokens = new(big.Int).SetBytes(msg.Maxtokens).String() + if consensus.IsDposName(msg.Id.Consensus) { + ci.StakingMinimum = new(big.Int).SetBytes(msg.Stakingminimum).String() + ci.StakingTotal = new(big.Int).SetBytes(msg.Totalstaking).String() + } + ci.GasPrice = new(big.Int).SetBytes(msg.Gasprice).String() + ci.NamePrice = new(big.Int).SetBytes(msg.Nameprice).String() + ci.TotalVotingPower = new(big.Int).SetBytes(msg.Totalvotingpower).String() + ci.VotingReward = new(big.Int).SetBytes(msg.Votingreward).String() +} + +func (ci *InOutChainInfo) MarshalJSON() ([]byte, error) { + return json.MarshalIndent(ci, "", " ") +} + +type InOutChainId struct { + Magic string + Public bool + Mainnet bool + Consensus string + Version int32 +} + +func (ci *InOutChainId) FromProto(msg *types.ChainId) { + ci.Magic = msg.Magic + ci.Public = msg.Public + ci.Mainnet = msg.Mainnet + ci.Consensus = msg.Consensus + ci.Version = msg.Version +} diff --git a/types/jsonrpc/zzz__chainstatus.go b/types/jsonrpc/zzz__chainstatus.go new file mode 100644 index 000000000..4f98cbbfa --- /dev/null +++ b/types/jsonrpc/zzz__chainstatus.go @@ -0,0 +1,42 @@ +package jsonrpc + +import ( + "encoding/json" + + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/internal/enc/hex" + "github.com/aergoio/aergo/v2/types" +) + +type InOutBlockchainStatus struct { + Hash string + Height uint64 + ConsensusInfo *json.RawMessage `json:",omitempty"` + ChainIdHash string + ChainStat *json.RawMessage `json:",omitempty"` + ChainInfo *InOutChainInfo `json:",omitempty"` +} + +func (bs *InOutBlockchainStatus) FromProtoHex(msg *types.BlockchainStatus) { + bs.Hash = hex.Encode(msg.BestBlockHash) + bs.Height = msg.BestHeight + bs.ChainIdHash = hex.Encode(msg.BestChainIdHash) +} + +func (bs *InOutBlockchainStatus) FromProtoBase58(msg *types.BlockchainStatus) { + bs.Hash = base58.Encode(msg.BestBlockHash) + bs.Height = msg.BestHeight + bs.ChainIdHash = base58.Encode(msg.BestChainIdHash) + + toJRM := func(s string) *json.RawMessage { + if len(s) > 0 { + m := json.RawMessage(s) + return &m + } + return nil + } + bs.ConsensusInfo = toJRM(msg.ConsensusInfo) + if msg.ChainInfo != nil { + bs.ChainInfo.FromProto(msg.ChainInfo) + } +} diff --git a/types/jsonrpc/zzz__peer.go b/types/jsonrpc/zzz__peer.go new file mode 100644 index 000000000..a4678db9b --- /dev/null +++ b/types/jsonrpc/zzz__peer.go @@ -0,0 +1,95 @@ +package jsonrpc + +import ( + "strconv" + "time" + + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +type InOutPeer struct { + Role string + Address InOutPeerAddress + BestBlock InOutBlockIdx + LastCheck time.Time + State string + Hidden bool + Self bool + Version string +} + +func (p *InOutPeer) FromProto(msg *types.Peer) { + p.Role = msg.AcceptedRole.String() + if msg.GetAddress() != nil { + p.Address.FromProto(msg.GetAddress()) + } + if msg.GetBestblock() != nil { + p.BestBlock.FromProto(msg.GetBestblock()) + } + p.LastCheck = time.Unix(0, msg.GetLashCheck()) + p.State = types.PeerState(msg.State).String() + p.Hidden = msg.Hidden + p.Self = msg.Selfpeer + if msg.Version != "" { + p.Version = msg.Version + } else { + p.Version = "(old)" + } +} + +type InOutPeerAddress struct { + Address string + Port string + PeerId string +} + +func (pa *InOutPeerAddress) FromProto(msg *types.PeerAddress) { + pa.Address = msg.GetAddress() + pa.Port = strconv.Itoa(int(msg.GetPort())) + pa.PeerId = base58.Encode(msg.GetPeerID()) +} + +type LongInOutPeer struct { + InOutPeer + ProducerIDs []string + Certificates []*InOutCert +} + +func (out *LongInOutPeer) FromProto(p *types.Peer) { + out.InOutPeer.FromProto(p) + + out.ProducerIDs = make([]string, len(p.Address.ProducerIDs)) + for i, pid := range p.Address.ProducerIDs { + out.ProducerIDs[i] = base58.Encode(pid) + } + + if p.Address.Role == types.PeerRole_Agent { + out.Certificates = make([]*InOutCert, len(p.Certificates)) + for i, cert := range p.Certificates { + out.Certificates[i] = &InOutCert{} + out.Certificates[i].FromProto(cert) + } + } +} + +type InOutCert struct { + CertVersion uint32 + ProducerID string + CreateTime time.Time + ExpireTime time.Time + AgentID string + Addresses []string +} + +func (out *InOutCert) FromProto(msg *types.AgentCertificate) { + out.CertVersion = msg.CertVersion + out.ProducerID = base58.Encode(msg.BPID) + out.AgentID = base58.Encode(msg.AgentID) + out.CreateTime = time.Unix(0, msg.CreateTime) + out.ExpireTime = time.Unix(0, msg.ExpireTime) + out.Addresses = []string{} + for _, ad := range msg.AgentAddress { + out.Addresses = append(out.Addresses, string(ad)) + } +} diff --git a/types/jsonrpc/zzz__tx.go b/types/jsonrpc/zzz__tx.go new file mode 100644 index 000000000..aef0fe91a --- /dev/null +++ b/types/jsonrpc/zzz__tx.go @@ -0,0 +1,146 @@ +package jsonrpc + +import ( + "errors" + "math/big" + + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +type InOutTx struct { + Hash string `json:",omitempty"` + Body *InOutTxBody `json:",omitempty"` +} + +func (t *InOutTx) FromProto(msg *types.Tx, payloadType EncodingType) { + t.Body = &InOutTxBody{} + if msg == nil { + return + } + t.Hash = base58.Encode(msg.Hash) + if msg.Body != nil { + t.Body.FromProto(msg.Body, payloadType) + } +} + +type InOutTxBody struct { + Nonce uint64 `json:",omitempty"` + Account string `json:",omitempty"` + Recipient string `json:",omitempty"` + Amount string `json:",omitempty"` + Payload string `json:",omitempty"` + GasLimit uint64 `json:",omitempty"` + GasPrice string `json:",omitempty"` + Type types.TxType `json:",omitempty"` + ChainIdHash string `json:",omitempty"` + Sign string `json:",omitempty"` +} + +func (tb *InOutTxBody) FromProto(msg *types.TxBody, payloadType EncodingType) { + tb.Nonce = msg.Nonce + if msg.Account != nil { + tb.Account = types.EncodeAddress(msg.Account) + } + if msg.Recipient != nil { + tb.Recipient = types.EncodeAddress(msg.Recipient) + } + if msg.Amount != nil { + tb.Amount = new(big.Int).SetBytes(msg.Amount).String() + } + switch payloadType { + case Raw: + tb.Payload = string(msg.Payload) + case Base58: + tb.Payload = base58.Encode(msg.Payload) + } + tb.GasLimit = msg.GasLimit + if msg.GasPrice != nil { + tb.GasPrice = new(big.Int).SetBytes(msg.GasPrice).String() + } + tb.ChainIdHash = base58.Encode(msg.ChainIdHash) + tb.Sign = base58.Encode(msg.Sign) + tb.Type = msg.Type +} + +func (tb *InOutTxBody) ToProto() (msg *types.TxBody, err error) { + if tb == nil { + return nil, errors.New("tx body is empty") + } + + msg.Nonce = tb.Nonce + if tb.Account != "" { + msg.Account, err = types.DecodeAddress(tb.Account) + if err != nil { + return nil, err + } + } + if tb.Recipient != "" { + msg.Recipient, err = types.DecodeAddress(tb.Recipient) + if err != nil { + return nil, err + } + } + if tb.Amount != "" { + amount, err := ParseUnit(tb.Amount) + if err != nil { + return nil, err + } + msg.Amount = amount.Bytes() + } + if tb.Payload != "" { + msg.Payload, err = base58.Decode(tb.Payload) + if err != nil { + return nil, err + } + } + msg.GasLimit = tb.GasLimit + if tb.GasPrice != "" { + price, err := ParseUnit(tb.GasPrice) + if err != nil { + return nil, err + } + msg.GasPrice = price.Bytes() + } + if tb.ChainIdHash != "" { + msg.ChainIdHash, err = base58.Decode(tb.ChainIdHash) + if err != nil { + return nil, err + } + } + if tb.Sign != "" { + msg.Sign, err = base58.Decode(tb.Sign) + if err != nil { + return nil, err + } + } + msg.Type = tb.Type + return msg, nil +} + +type InOutTxInBlock struct { + TxIdx *InOutTxIdx + Tx *InOutTx +} + +func (tib *InOutTxInBlock) FromProto(txInBlock *types.TxInBlock, payloadType EncodingType) { + tib.TxIdx = &InOutTxIdx{} + tib.Tx = &InOutTx{} + + if txInBlock.GetTxIdx() != nil { + tib.TxIdx.FromProto(txInBlock.GetTxIdx()) + } + if txInBlock.GetTx() != nil { + tib.Tx.FromProto(txInBlock.GetTx(), payloadType) + } +} + +type InOutTxIdx struct { + BlockHash string + Idx int32 +} + +func (ti *InOutTxIdx) FromProto(msg *types.TxIdx) { + ti.BlockHash = base58.Encode(msg.GetBlockHash()) + ti.Idx = msg.GetIdx() +} From f92c9928764425cf446a0875c3ec9d1c574c0a79 Mon Sep 17 00:00:00 2001 From: kch Date: Thu, 16 Nov 2023 09:06:11 +0000 Subject: [PATCH 022/134] fromProto to Conv functions --- cmd/aergocli/cmd/committx.go | 3 +- cmd/aergocli/cmd/contract.go | 3 +- cmd/aergocli/cmd/event.go | 6 +- cmd/aergocli/cmd/gettx.go | 4 +- cmd/aergocli/cmd/sendtx.go | 6 +- rpc/web3/v1.go | 8 +- tools/mpdumpdiag/main.go | 2 +- types/jsonrpc/base58addr.go | 121 ------------------------------ types/jsonrpc/base64ToHex.go | 20 ----- types/jsonrpc/convTx.go | 16 +--- types/jsonrpc/convTx_test.go | 4 +- types/jsonrpc/zzz__block.go | 73 ++++++++++-------- types/jsonrpc/zzz__chainInfo.go | 51 ++++++------- types/jsonrpc/zzz__chainstatus.go | 38 +++++----- types/jsonrpc/zzz__commit.go | 33 ++++++++ types/jsonrpc/zzz__event.go | 30 ++++++++ types/jsonrpc/zzz__peer.go | 96 +++++++++++++----------- types/jsonrpc/zzz__tx.go | 77 ++++++++++--------- 18 files changed, 269 insertions(+), 322 deletions(-) delete mode 100644 types/jsonrpc/base64ToHex.go create mode 100644 types/jsonrpc/zzz__commit.go create mode 100644 types/jsonrpc/zzz__event.go diff --git a/cmd/aergocli/cmd/committx.go b/cmd/aergocli/cmd/committx.go index 6764d7ba1..abdd0eed1 100644 --- a/cmd/aergocli/cmd/committx.go +++ b/cmd/aergocli/cmd/committx.go @@ -67,7 +67,8 @@ func execCommitTX(cmd *cobra.Command, args []string) error { if err != nil { return errors.New("Failed request to aergo server\n" + err.Error()) } - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvCommitResultList(msg) + cmd.Println(jsonrpc.B58JSON(res)) } return nil } diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 531f5e664..1fb28ff21 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -350,7 +350,8 @@ func runCallCmd(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to commit tx: %v", err.Error()) } - cmd.Println(jsonrpc.JSON(msgs.Results[0])) + res := jsonrpc.ConvCommitResult(msgs.Results[0]) + cmd.Println(jsonrpc.B58JSON(res)) } return nil } diff --git a/cmd/aergocli/cmd/event.go b/cmd/aergocli/cmd/event.go index bfcd087ec..207280325 100644 --- a/cmd/aergocli/cmd/event.go +++ b/cmd/aergocli/cmd/event.go @@ -82,7 +82,8 @@ func execListEvent(cmd *cobra.Command, args []string) { return } for _, event := range events.GetEvents() { - cmd.Println(jsonrpc.JSON(event)) + res := jsonrpc.ConvEvent(event) + cmd.Println(jsonrpc.B58JSON(res)) } } @@ -108,6 +109,7 @@ func execStreamEvent(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(jsonrpc.JSON(event)) + res := jsonrpc.ConvEvent(event) + cmd.Println(jsonrpc.B58JSON(res)) } } diff --git a/cmd/aergocli/cmd/gettx.go b/cmd/aergocli/cmd/gettx.go index a2b90f784..3791bcf34 100644 --- a/cmd/aergocli/cmd/gettx.go +++ b/cmd/aergocli/cmd/gettx.go @@ -41,14 +41,14 @@ func execGetTX(cmd *cobra.Command, args []string) { } msg, err := client.GetTX(context.Background(), &aergorpc.SingleBytes{Value: txHash}) if err == nil { - cmd.Println(jsonrpc.ConvTxEx(msg, payloadEncodingType)) + cmd.Println(jsonrpc.ConvTx(msg, payloadEncodingType)) } else { msgblock, err := client.GetBlockTX(context.Background(), &aergorpc.SingleBytes{Value: txHash}) if err != nil { cmd.Printf("Failed: %s", err.Error()) return } - cmd.Println(jsonrpc.ConvTxInBlockEx(msgblock, payloadEncodingType)) + cmd.Println(jsonrpc.ConvTxInBlock(msgblock, payloadEncodingType)) } } diff --git a/cmd/aergocli/cmd/sendtx.go b/cmd/aergocli/cmd/sendtx.go index a77c293f8..c6ee7d6e4 100644 --- a/cmd/aergocli/cmd/sendtx.go +++ b/cmd/aergocli/cmd/sendtx.go @@ -100,12 +100,14 @@ func sendTX(cmd *cobra.Command, tx *types.Tx, account []byte) string { if err != nil { return "Failed request to aergo server: " + err.Error() } - return jsonrpc.JSON(msgs.Results[0]) + res := jsonrpc.ConvCommitResult(msgs.Results[0]) + return jsonrpc.B58JSON(res) } else { msg, err := client.SendTX(context.Background(), tx) if err != nil { return "Failed request to aergo sever: " + err.Error() } - return jsonrpc.JSON(msg) + res := jsonrpc.ConvCommitResult(msg) + return jsonrpc.B58JSON(res) } } diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index 04c4f25c0..ab59331f5 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -707,14 +707,14 @@ func (api *Web3APIv1) GetTX() (handler http.Handler, ok bool) { msg, err := api.rpc.GetTX(api.request.Context(), request) if err == nil { - return commonResponseHandler(jsonrpc.ConvTxEx(msg, jsonrpc.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTx(msg, jsonrpc.Base58), nil), true } else { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(jsonrpc.ConvTxInBlockEx(msgblock, jsonrpc.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxInBlock(msgblock, jsonrpc.Base58), nil), true } } @@ -741,14 +741,14 @@ func (api *Web3APIv1) GetBlockTX() (handler http.Handler, ok bool) { msg, err := api.rpc.GetTX(api.request.Context(), request) if err == nil { - return commonResponseHandler(jsonrpc.ConvTxEx(msg, jsonrpc.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTx(msg, jsonrpc.Base58), nil), true } else { msgblock, err := api.rpc.GetBlockTX(api.request.Context(), request) if err != nil { return commonResponseHandler(&types.Empty{}, err), true } - return commonResponseHandler(jsonrpc.ConvTxInBlockEx(msgblock, jsonrpc.Base58), nil), true + return commonResponseHandler(jsonrpc.ConvTxInBlock(msgblock, jsonrpc.Base58), nil), true } } diff --git a/tools/mpdumpdiag/main.go b/tools/mpdumpdiag/main.go index c869e4afd..5d997e3dd 100644 --- a/tools/mpdumpdiag/main.go +++ b/tools/mpdumpdiag/main.go @@ -82,7 +82,7 @@ func runPrintCmd(cmd *cobra.Command, args []string) { count++ //mp.put(types.NewTransaction(&buf)) // nolint: errcheck - out = append(out, jsonrpc.ConvTx(types.NewTransaction(&buf).GetTx())) + out = append(out, jsonrpc.ConvTx(types.NewTransaction(&buf).GetTx(), jsonrpc.Base58)) } b, e := json.MarshalIndent(out, "", " ") if e == nil { diff --git a/types/jsonrpc/base58addr.go b/types/jsonrpc/base58addr.go index 4f186ff2a..69bcab84a 100644 --- a/types/jsonrpc/base58addr.go +++ b/types/jsonrpc/base58addr.go @@ -4,8 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "math/big" - "strconv" "time" "github.com/aergoio/aergo/v2/internal/enc/base58" @@ -115,97 +113,6 @@ func ParseBase58TxBody(jsonTx []byte) (*types.TxBody, error) { return body, nil } -func ConvTxEx(tx *types.Tx, payloadType EncodingType) *InOutTx { - out := &InOutTx{Body: &InOutTxBody{}} - if tx == nil { - return out - } - out.Hash = base58.Encode(tx.Hash) - out.Body.Nonce = tx.Body.Nonce - if tx.Body.Account != nil { - out.Body.Account = types.EncodeAddress(tx.Body.Account) - } - if tx.Body.Recipient != nil { - out.Body.Recipient = types.EncodeAddress(tx.Body.Recipient) - } - if tx.Body.Amount != nil { - out.Body.Amount = new(big.Int).SetBytes(tx.Body.Amount).String() - } - switch payloadType { - case Raw: - out.Body.Payload = string(tx.Body.Payload) - case Base58: - out.Body.Payload = base58.Encode(tx.Body.Payload) - } - out.Body.GasLimit = tx.Body.GasLimit - if tx.Body.GasPrice != nil { - out.Body.GasPrice = new(big.Int).SetBytes(tx.Body.GasPrice).String() - } - out.Body.ChainIdHash = base58.Encode(tx.Body.ChainIdHash) - out.Body.Sign = base58.Encode(tx.Body.Sign) - out.Body.Type = tx.Body.Type - return out -} - -func ConvTxInBlockEx(txInBlock *types.TxInBlock, payloadType EncodingType) *InOutTxInBlock { - out := &InOutTxInBlock{TxIdx: &InOutTxIdx{}, Tx: &InOutTx{}} - out.TxIdx.BlockHash = base58.Encode(txInBlock.GetTxIdx().GetBlockHash()) - out.TxIdx.Idx = txInBlock.GetTxIdx().GetIdx() - out.Tx = ConvTxEx(txInBlock.GetTx(), payloadType) - return out -} - -func ConvBlock(b *types.Block) *InOutBlock { - out := &InOutBlock{} - if b != nil { - out.Hash = base58.Encode(b.Hash) - out.Header.ChainID = base58.Encode(b.GetHeader().GetChainID()) - out.Header.Version = types.DecodeChainIdVersion(b.GetHeader().GetChainID()) - out.Header.PrevBlockHash = base58.Encode(b.GetHeader().GetPrevBlockHash()) - out.Header.BlockNo = b.GetHeader().GetBlockNo() - out.Header.Timestamp = b.GetHeader().GetTimestamp() - out.Header.BlockRootHash = base58.Encode(b.GetHeader().GetBlocksRootHash()) - out.Header.TxRootHash = base58.Encode(b.GetHeader().GetTxsRootHash()) - out.Header.ReceiptsRootHash = base58.Encode(b.GetHeader().GetReceiptsRootHash()) - out.Header.Confirms = b.GetHeader().GetConfirms() - out.Header.PubKey = base58.Encode(b.GetHeader().GetPubKey()) - out.Header.Sign = base58.Encode(b.GetHeader().GetSign()) - if b.GetHeader().GetCoinbaseAccount() != nil { - out.Header.CoinbaseAccount = types.EncodeAddress(b.GetHeader().GetCoinbaseAccount()) - } - if consensus := b.GetHeader().GetConsensus(); consensus != nil { - out.Header.Consensus = types.EncodeAddress(consensus) - } - - if b.Body != nil { - for _, tx := range b.Body.Txs { - out.Body.Txs = append(out.Body.Txs, ConvTx(tx)) - } - } - } - return out -} - -func ConvPeer(p *types.Peer) *InOutPeer { - out := &InOutPeer{} - out.Role = p.AcceptedRole.String() - out.Address.Address = p.GetAddress().GetAddress() - out.Address.Port = strconv.Itoa(int(p.GetAddress().GetPort())) - out.Address.PeerId = base58.Encode(p.GetAddress().GetPeerID()) - out.LastCheck = time.Unix(0, p.GetLashCheck()) - out.BestBlock.BlockNo = p.GetBestblock().GetBlockNo() - out.BestBlock.BlockHash = base58.Encode(p.GetBestblock().GetBlockHash()) - out.State = types.PeerState(p.State).String() - out.Hidden = p.Hidden - out.Self = p.Selfpeer - if p.Version != "" { - out.Version = p.Version - } else { - out.Version = "(old)" - } - return out -} - func ConvPeerLong(p *types.Peer) *LongInOutPeer { out := &LongInOutPeer{InOutPeer: *ConvPeer(p)} out.ProducerIDs = make([]string, len(p.Address.ProducerIDs)) @@ -228,34 +135,6 @@ func ConvPeerLong(p *types.Peer) *LongInOutPeer { return out } -func ConvBlockchainStatus(in *types.BlockchainStatus) string { - out := &InOutBlockchainStatus{} - if in == nil { - return "" - } - out.Hash = base58.Encode(in.BestBlockHash) - out.Height = in.BestHeight - - out.ChainIdHash = base58.Encode(in.BestChainIdHash) - - toJRM := func(s string) *json.RawMessage { - if len(s) > 0 { - m := json.RawMessage(s) - return &m - } - return nil - } - out.ConsensusInfo = toJRM(in.ConsensusInfo) - if in.ChainInfo != nil { - out.ChainInfo = convChainInfo(in.ChainInfo) - } - jsonout, err := json.Marshal(out) - if err != nil { - return "" - } - return string(jsonout) -} - func BlockConvBase58Addr(b *types.Block) string { return toString(ConvBlock(b)) } diff --git a/types/jsonrpc/base64ToHex.go b/types/jsonrpc/base64ToHex.go deleted file mode 100644 index a018268bc..000000000 --- a/types/jsonrpc/base64ToHex.go +++ /dev/null @@ -1,20 +0,0 @@ -package jsonrpc - -import ( - "encoding/json" - - "github.com/aergoio/aergo/v2/internal/enc/hex" - "github.com/aergoio/aergo/v2/types" -) - -func ConvHexBlockchainStatus(in *types.BlockchainStatus) string { - out := &InOutBlockchainStatus{} - out.Hash = hex.Encode(in.BestBlockHash) - out.Height = in.BestHeight - out.ChainIdHash = hex.Encode(in.BestChainIdHash) - jsonout, err := json.Marshal(out) - if err != nil { - return "" - } - return string(jsonout) -} diff --git a/types/jsonrpc/convTx.go b/types/jsonrpc/convTx.go index 7b93f804a..13afa54be 100644 --- a/types/jsonrpc/convTx.go +++ b/types/jsonrpc/convTx.go @@ -22,27 +22,19 @@ func (t *InOutTxInBlock) String() string { } func TxConvBase58Addr(tx *types.Tx) string { - return toString(ConvTx(tx)) + return toString(ConvTx(tx, Base58)) } func TxConvBase58AddrEx(tx *types.Tx, payloadType EncodingType) string { switch payloadType { case Raw: - return toString(ConvTxEx(tx, Raw)) + return toString(ConvTx(tx, Raw)) case Base58: - return toString(ConvTxEx(tx, Base58)) + return toString(ConvTx(tx, Base58)) } return "" } func TxInBlockConvBase58Addr(txInBlock *types.TxInBlock) string { - return toString(ConvTxInBlock(txInBlock)) -} - -func ConvTx(tx *types.Tx) *InOutTx { - return ConvTxEx(tx, Base58) -} - -func ConvTxInBlock(txInBlock *types.TxInBlock) *InOutTxInBlock { - return ConvTxInBlockEx(txInBlock, Base58) + return toString(ConvTxInBlock(txInBlock, Base58)) } diff --git a/types/jsonrpc/convTx_test.go b/types/jsonrpc/convTx_test.go index ba4f70cb5..9be1ca760 100644 --- a/types/jsonrpc/convTx_test.go +++ b/types/jsonrpc/convTx_test.go @@ -9,8 +9,8 @@ import ( func TestConvTxEx(t *testing.T) { testTx := &types.Tx{Body: &types.TxBody{Payload: []byte("{\"Name\":\"v1createName\",\"Args\":[\"honggildong3\"]}")}} - result := toString(ConvTxEx(testTx, Base58)) + result := toString(ConvTx(testTx, Base58)) assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"22MZAFWvxtVWehpgwEVxrvoqGL5xmcPmyLBiwraDfxRwKUNrV9tmhuB7Uu6ZeJWvp\"\n }\n}", result, "") - result = toString(ConvTxEx(testTx, Raw)) + result = toString(ConvTx(testTx, Raw)) assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"{\\\"Name\\\":\\\"v1createName\\\",\\\"Args\\\":[\\\"honggildong3\\\"]}\"\n }\n}", result, "") } diff --git a/types/jsonrpc/zzz__block.go b/types/jsonrpc/zzz__block.go index e007c7530..a5e47ba61 100644 --- a/types/jsonrpc/zzz__block.go +++ b/types/jsonrpc/zzz__block.go @@ -5,39 +5,26 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutBlock struct { - Hash string - Header InOutBlockHeader - Body InOutBlockBody -} - -func (b *InOutBlock) FromProto(msg *types.Block) { +func ConvBlock(msg *types.Block) *InOutBlock { + b := &InOutBlock{} b.Hash = base58.Encode(msg.Hash) if msg.Header != nil { - b.Header.FromProto(msg.Header) + b.Header = *ConvBlockHeader(msg.Header) } if msg.Body != nil { - b.Body.FromProto(msg.Body) + b.Body = *ConvBlockBody(msg.Body) } + return b } -type InOutBlockHeader struct { - ChainID string - Version int32 - PrevBlockHash string - BlockNo uint64 - Timestamp int64 - BlockRootHash string - TxRootHash string - ReceiptsRootHash string - Confirms uint64 - PubKey string - Sign string - CoinbaseAccount string - Consensus string +type InOutBlock struct { + Hash string + Header InOutBlockHeader + Body InOutBlockBody } -func (bh *InOutBlockHeader) FromProto(msg *types.BlockHeader) { +func ConvBlockHeader(msg *types.BlockHeader) *InOutBlockHeader { + bh := &InOutBlockHeader{} bh.ChainID = base58.Encode(msg.GetChainID()) bh.Version = types.DecodeChainIdVersion(msg.GetChainID()) bh.PrevBlockHash = base58.Encode(msg.GetPrevBlockHash()) @@ -55,26 +42,46 @@ func (bh *InOutBlockHeader) FromProto(msg *types.BlockHeader) { if consensus := msg.GetConsensus(); consensus != nil { bh.Consensus = types.EncodeAddress(consensus) } + return bh } -type InOutBlockBody struct { - Txs []*InOutTx +type InOutBlockHeader struct { + ChainID string + Version int32 + PrevBlockHash string + BlockNo uint64 + Timestamp int64 + BlockRootHash string + TxRootHash string + ReceiptsRootHash string + Confirms uint64 + PubKey string + Sign string + CoinbaseAccount string + Consensus string } -func (bb *InOutBlockBody) FromProto(msg *types.BlockBody) { +func ConvBlockBody(msg *types.BlockBody) *InOutBlockBody { + bb := &InOutBlockBody{} bb.Txs = make([]*InOutTx, len(msg.Txs)) for i, tx := range msg.Txs { - bb.Txs[i] = &InOutTx{} - bb.Txs[i].FromProto(tx, Base58) + bb.Txs[i] = ConvTx(tx, Base58) } + return bb } -type InOutBlockIdx struct { - BlockHash string - BlockNo uint64 +type InOutBlockBody struct { + Txs []*InOutTx } -func (bh *InOutBlockIdx) FromProto(msg *types.NewBlockNotice) { +func ConvBlockIdx(msg *types.NewBlockNotice) *InOutBlockIdx { + bh := &InOutBlockIdx{} bh.BlockNo = msg.GetBlockNo() bh.BlockHash = base58.Encode(msg.GetBlockHash()) + return bh +} + +type InOutBlockIdx struct { + BlockHash string + BlockNo uint64 } diff --git a/types/jsonrpc/zzz__chainInfo.go b/types/jsonrpc/zzz__chainInfo.go index 64edee1a1..1bf27dc47 100644 --- a/types/jsonrpc/zzz__chainInfo.go +++ b/types/jsonrpc/zzz__chainInfo.go @@ -1,29 +1,16 @@ package jsonrpc import ( - "encoding/json" "math/big" "github.com/aergoio/aergo/v2/consensus" "github.com/aergoio/aergo/v2/types" ) -type InOutChainInfo struct { - Chainid InOutChainId - BpNumber uint32 - MaxBlockSize uint64 - MaxTokens string - StakingMinimum string `json:",omitempty"` - StakingTotal string `json:",omitempty"` - GasPrice string `json:",omitempty"` - NamePrice string `json:",omitempty"` - TotalVotingPower string `json:",omitempty"` - VotingReward string `json:",omitempty"` -} - -func (ci *InOutChainInfo) FromProto(msg *types.ChainInfo) { +func ConvChainInfo(msg *types.ChainInfo) *InOutChainInfo { + ci := &InOutChainInfo{} if msg.Id != nil { - ci.Chainid.FromProto(msg.Id) + ci.Chainid = *ConvChainId(msg.Id) } ci.MaxTokens = new(big.Int).SetBytes(msg.Maxtokens).String() if consensus.IsDposName(msg.Id.Consensus) { @@ -34,10 +21,30 @@ func (ci *InOutChainInfo) FromProto(msg *types.ChainInfo) { ci.NamePrice = new(big.Int).SetBytes(msg.Nameprice).String() ci.TotalVotingPower = new(big.Int).SetBytes(msg.Totalvotingpower).String() ci.VotingReward = new(big.Int).SetBytes(msg.Votingreward).String() + return ci +} + +type InOutChainInfo struct { + Chainid InOutChainId + BpNumber uint32 + MaxBlockSize uint64 + MaxTokens string + StakingMinimum string `json:",omitempty"` + StakingTotal string `json:",omitempty"` + GasPrice string `json:",omitempty"` + NamePrice string `json:",omitempty"` + TotalVotingPower string `json:",omitempty"` + VotingReward string `json:",omitempty"` } -func (ci *InOutChainInfo) MarshalJSON() ([]byte, error) { - return json.MarshalIndent(ci, "", " ") +func ConvChainId(msg *types.ChainId) *InOutChainId { + ci := &InOutChainId{} + ci.Magic = msg.Magic + ci.Public = msg.Public + ci.Mainnet = msg.Mainnet + ci.Consensus = msg.Consensus + ci.Version = msg.Version + return ci } type InOutChainId struct { @@ -47,11 +54,3 @@ type InOutChainId struct { Consensus string Version int32 } - -func (ci *InOutChainId) FromProto(msg *types.ChainId) { - ci.Magic = msg.Magic - ci.Public = msg.Public - ci.Mainnet = msg.Mainnet - ci.Consensus = msg.Consensus - ci.Version = msg.Version -} diff --git a/types/jsonrpc/zzz__chainstatus.go b/types/jsonrpc/zzz__chainstatus.go index 4f98cbbfa..cfff9d257 100644 --- a/types/jsonrpc/zzz__chainstatus.go +++ b/types/jsonrpc/zzz__chainstatus.go @@ -8,22 +8,8 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutBlockchainStatus struct { - Hash string - Height uint64 - ConsensusInfo *json.RawMessage `json:",omitempty"` - ChainIdHash string - ChainStat *json.RawMessage `json:",omitempty"` - ChainInfo *InOutChainInfo `json:",omitempty"` -} - -func (bs *InOutBlockchainStatus) FromProtoHex(msg *types.BlockchainStatus) { - bs.Hash = hex.Encode(msg.BestBlockHash) - bs.Height = msg.BestHeight - bs.ChainIdHash = hex.Encode(msg.BestChainIdHash) -} - -func (bs *InOutBlockchainStatus) FromProtoBase58(msg *types.BlockchainStatus) { +func ConvBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { + bs := &InOutBlockchainStatus{} bs.Hash = base58.Encode(msg.BestBlockHash) bs.Height = msg.BestHeight bs.ChainIdHash = base58.Encode(msg.BestChainIdHash) @@ -37,6 +23,24 @@ func (bs *InOutBlockchainStatus) FromProtoBase58(msg *types.BlockchainStatus) { } bs.ConsensusInfo = toJRM(msg.ConsensusInfo) if msg.ChainInfo != nil { - bs.ChainInfo.FromProto(msg.ChainInfo) + bs.ChainInfo = ConvChainInfo(msg.ChainInfo) } + return bs +} + +func ConvHexBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { + bs := &InOutBlockchainStatus{} + bs.Hash = hex.Encode(msg.BestBlockHash) + bs.Height = msg.BestHeight + bs.ChainIdHash = hex.Encode(msg.BestChainIdHash) + return bs +} + +type InOutBlockchainStatus struct { + Hash string + Height uint64 + ConsensusInfo *json.RawMessage `json:",omitempty"` + ChainIdHash string + ChainStat *json.RawMessage `json:",omitempty"` + ChainInfo *InOutChainInfo `json:",omitempty"` } diff --git a/types/jsonrpc/zzz__commit.go b/types/jsonrpc/zzz__commit.go new file mode 100644 index 000000000..c3002da3c --- /dev/null +++ b/types/jsonrpc/zzz__commit.go @@ -0,0 +1,33 @@ +package jsonrpc + +import ( + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +func ConvCommitResultList(msg *types.CommitResultList) *InOutCommitResultList { + c := &InOutCommitResultList{} + c.Results = make([]*InOutCommitResult, len(msg.Results)) + for i, result := range msg.Results { + c.Results[i] = ConvCommitResult(result) + } + return c +} + +type InOutCommitResultList struct { + Results []*InOutCommitResult +} + +func ConvCommitResult(msg *types.CommitResult) *InOutCommitResult { + c := &InOutCommitResult{} + c.Hash = base58.Encode(msg.Hash) + c.Error = msg.Error + c.Detail = msg.Detail + return c +} + +type InOutCommitResult struct { + Hash string + Error types.CommitStatus + Detail string +} diff --git a/types/jsonrpc/zzz__event.go b/types/jsonrpc/zzz__event.go new file mode 100644 index 000000000..9f3816398 --- /dev/null +++ b/types/jsonrpc/zzz__event.go @@ -0,0 +1,30 @@ +package jsonrpc + +import ( + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +func ConvEvent(msg *types.Event) *InOutEvent { + e := &InOutEvent{} + e.ContractAddress = base58.Encode(msg.ContractAddress) + e.EventName = msg.EventName + e.JsonArgs = msg.JsonArgs + e.EventIdx = msg.EventIdx + e.TxHash = base58.Encode(msg.TxHash) + e.BlockHash = base58.Encode(msg.BlockHash) + e.BlockNo = msg.BlockNo + e.TxIndex = msg.TxIndex + return e +} + +type InOutEvent struct { + ContractAddress string + EventName string + JsonArgs string + EventIdx int32 + TxHash string + BlockHash string + BlockNo uint64 + TxIndex int32 +} diff --git a/types/jsonrpc/zzz__peer.go b/types/jsonrpc/zzz__peer.go index a4678db9b..d6ca1fe5b 100644 --- a/types/jsonrpc/zzz__peer.go +++ b/types/jsonrpc/zzz__peer.go @@ -8,24 +8,14 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutPeer struct { - Role string - Address InOutPeerAddress - BestBlock InOutBlockIdx - LastCheck time.Time - State string - Hidden bool - Self bool - Version string -} - -func (p *InOutPeer) FromProto(msg *types.Peer) { +func ConvPeer(msg *types.Peer) *InOutPeer { + p := &InOutPeer{} p.Role = msg.AcceptedRole.String() if msg.GetAddress() != nil { - p.Address.FromProto(msg.GetAddress()) + p.Address = *ConvPeerAddress(msg.GetAddress()) } if msg.GetBestblock() != nil { - p.BestBlock.FromProto(msg.GetBestblock()) + p.BestBlock = *ConvBlockIdx(msg.GetBestblock()) } p.LastCheck = time.Unix(0, msg.GetLashCheck()) p.State = types.PeerState(msg.State).String() @@ -36,6 +26,26 @@ func (p *InOutPeer) FromProto(msg *types.Peer) { } else { p.Version = "(old)" } + return p +} + +type InOutPeer struct { + Role string + Address InOutPeerAddress + BestBlock InOutBlockIdx + LastCheck time.Time + State string + Hidden bool + Self bool + Version string +} + +func ConvPeerAddress(msg *types.PeerAddress) *InOutPeerAddress { + pa := &InOutPeerAddress{} + pa.Address = msg.GetAddress() + pa.Port = strconv.Itoa(int(msg.GetPort())) + pa.PeerId = base58.Encode(msg.GetPeerID()) + return pa } type InOutPeerAddress struct { @@ -44,10 +54,23 @@ type InOutPeerAddress struct { PeerId string } -func (pa *InOutPeerAddress) FromProto(msg *types.PeerAddress) { - pa.Address = msg.GetAddress() - pa.Port = strconv.Itoa(int(msg.GetPort())) - pa.PeerId = base58.Encode(msg.GetPeerID()) +func ConvLongPeer(msg *types.Peer) *LongInOutPeer { + p := &LongInOutPeer{} + p.InOutPeer = *ConvPeer(msg) + + p.ProducerIDs = make([]string, len(msg.Address.ProducerIDs)) + for i, pid := range msg.Address.ProducerIDs { + p.ProducerIDs[i] = base58.Encode(pid) + } + + if msg.Address.Role == types.PeerRole_Agent { + p.Certificates = make([]*InOutCert, len(msg.Certificates)) + for i, cert := range msg.Certificates { + p.Certificates[i] = &InOutCert{} + p.Certificates[i] = ConvCert(cert) + } + } + return p } type LongInOutPeer struct { @@ -56,21 +79,18 @@ type LongInOutPeer struct { Certificates []*InOutCert } -func (out *LongInOutPeer) FromProto(p *types.Peer) { - out.InOutPeer.FromProto(p) - - out.ProducerIDs = make([]string, len(p.Address.ProducerIDs)) - for i, pid := range p.Address.ProducerIDs { - out.ProducerIDs[i] = base58.Encode(pid) - } - - if p.Address.Role == types.PeerRole_Agent { - out.Certificates = make([]*InOutCert, len(p.Certificates)) - for i, cert := range p.Certificates { - out.Certificates[i] = &InOutCert{} - out.Certificates[i].FromProto(cert) - } +func ConvCert(msg *types.AgentCertificate) *InOutCert { + c := &InOutCert{} + c.CertVersion = msg.CertVersion + c.ProducerID = base58.Encode(msg.BPID) + c.AgentID = base58.Encode(msg.AgentID) + c.CreateTime = time.Unix(0, msg.CreateTime) + c.ExpireTime = time.Unix(0, msg.ExpireTime) + c.Addresses = []string{} + for _, ad := range msg.AgentAddress { + c.Addresses = append(c.Addresses, string(ad)) } + return c } type InOutCert struct { @@ -81,15 +101,3 @@ type InOutCert struct { AgentID string Addresses []string } - -func (out *InOutCert) FromProto(msg *types.AgentCertificate) { - out.CertVersion = msg.CertVersion - out.ProducerID = base58.Encode(msg.BPID) - out.AgentID = base58.Encode(msg.AgentID) - out.CreateTime = time.Unix(0, msg.CreateTime) - out.ExpireTime = time.Unix(0, msg.ExpireTime) - out.Addresses = []string{} - for _, ad := range msg.AgentAddress { - out.Addresses = append(out.Addresses, string(ad)) - } -} diff --git a/types/jsonrpc/zzz__tx.go b/types/jsonrpc/zzz__tx.go index aef0fe91a..c30004735 100644 --- a/types/jsonrpc/zzz__tx.go +++ b/types/jsonrpc/zzz__tx.go @@ -8,36 +8,26 @@ import ( "github.com/aergoio/aergo/v2/types" ) -type InOutTx struct { - Hash string `json:",omitempty"` - Body *InOutTxBody `json:",omitempty"` -} - -func (t *InOutTx) FromProto(msg *types.Tx, payloadType EncodingType) { - t.Body = &InOutTxBody{} +func ConvTx(msg *types.Tx, payloadType EncodingType) (tx *InOutTx) { + tx = &InOutTx{} + tx.Body = &InOutTxBody{} if msg == nil { return } - t.Hash = base58.Encode(msg.Hash) + tx.Hash = base58.Encode(msg.Hash) if msg.Body != nil { - t.Body.FromProto(msg.Body, payloadType) + tx.Body = ConvTxBody(msg.Body, payloadType) } + return tx } -type InOutTxBody struct { - Nonce uint64 `json:",omitempty"` - Account string `json:",omitempty"` - Recipient string `json:",omitempty"` - Amount string `json:",omitempty"` - Payload string `json:",omitempty"` - GasLimit uint64 `json:",omitempty"` - GasPrice string `json:",omitempty"` - Type types.TxType `json:",omitempty"` - ChainIdHash string `json:",omitempty"` - Sign string `json:",omitempty"` +type InOutTx struct { + Hash string `json:",omitempty"` + Body *InOutTxBody `json:",omitempty"` } -func (tb *InOutTxBody) FromProto(msg *types.TxBody, payloadType EncodingType) { +func ConvTxBody(msg *types.TxBody, payloadType EncodingType) *InOutTxBody { + tb := &InOutTxBody{} tb.Nonce = msg.Nonce if msg.Account != nil { tb.Account = types.EncodeAddress(msg.Account) @@ -61,12 +51,14 @@ func (tb *InOutTxBody) FromProto(msg *types.TxBody, payloadType EncodingType) { tb.ChainIdHash = base58.Encode(msg.ChainIdHash) tb.Sign = base58.Encode(msg.Sign) tb.Type = msg.Type + return tb } -func (tb *InOutTxBody) ToProto() (msg *types.TxBody, err error) { +func ParseTxBody(tb *InOutTxBody) (msg *types.TxBody, err error) { if tb == nil { return nil, errors.New("tx body is empty") } + msg = &types.TxBody{} msg.Nonce = tb.Nonce if tb.Account != "" { @@ -118,29 +110,46 @@ func (tb *InOutTxBody) ToProto() (msg *types.TxBody, err error) { return msg, nil } -type InOutTxInBlock struct { - TxIdx *InOutTxIdx - Tx *InOutTx +type InOutTxBody struct { + Nonce uint64 `json:",omitempty"` + Account string `json:",omitempty"` + Recipient string `json:",omitempty"` + Amount string `json:",omitempty"` + Payload string `json:",omitempty"` + GasLimit uint64 `json:",omitempty"` + GasPrice string `json:",omitempty"` + Type types.TxType `json:",omitempty"` + ChainIdHash string `json:",omitempty"` + Sign string `json:",omitempty"` } -func (tib *InOutTxInBlock) FromProto(txInBlock *types.TxInBlock, payloadType EncodingType) { +func ConvTxInBlock(msg *types.TxInBlock, payloadType EncodingType) *InOutTxInBlock { + tib := &InOutTxInBlock{} tib.TxIdx = &InOutTxIdx{} tib.Tx = &InOutTx{} - if txInBlock.GetTxIdx() != nil { - tib.TxIdx.FromProto(txInBlock.GetTxIdx()) + if msg.GetTxIdx() != nil { + tib.TxIdx = ConvTxIdx(msg.GetTxIdx()) } - if txInBlock.GetTx() != nil { - tib.Tx.FromProto(txInBlock.GetTx(), payloadType) + if msg.GetTx() != nil { + tib.Tx = ConvTx(msg.GetTx(), payloadType) } + return tib } -type InOutTxIdx struct { - BlockHash string - Idx int32 +type InOutTxInBlock struct { + TxIdx *InOutTxIdx + Tx *InOutTx } -func (ti *InOutTxIdx) FromProto(msg *types.TxIdx) { +func ConvTxIdx(msg *types.TxIdx) *InOutTxIdx { + ti := &InOutTxIdx{} ti.BlockHash = base58.Encode(msg.GetBlockHash()) ti.Idx = msg.GetIdx() + return ti +} + +type InOutTxIdx struct { + BlockHash string + Idx int32 } From 6bb0b2cc662855cfe3ebc9b3b3ed500edb418b5f Mon Sep 17 00:00:00 2001 From: kch Date: Fri, 17 Nov 2023 03:33:14 +0000 Subject: [PATCH 023/134] tidy jsonrpc --- cmd/aergocli/cmd/chaininfo.go | 3 +- cmd/aergocli/cmd/contract.go | 6 +- cmd/aergocli/cmd/getblock.go | 6 +- cmd/aergocli/cmd/getpeers.go | 9 +- cmd/aergocli/cmd/listblocks.go | 3 +- cmd/aergocli/cmd/metric.go | 3 +- cmd/aergocli/cmd/receipt.go | 3 +- cmd/aergocli/cmd/signtx.go | 9 +- cmd/aergocli/cmd/vote.go | 3 +- cmd/colaris/cmd/metric.go | 3 +- mempool/mempool_test.go | 2 +- types/jsonrpc/base58addr.go | 170 ------------------ types/jsonrpc/convChaininfo.go | 40 ----- types/jsonrpc/convTx.go | 26 +-- types/jsonrpc/convTx_test.go | 16 -- types/jsonrpc/zzz__block.go | 45 ++++- types/jsonrpc/zzz__block_test.go | 52 ++++++ types/jsonrpc/zzz__chainInfo.go | 85 ++++++++- types/jsonrpc/zzz__chainstatus.go | 46 ----- types/jsonrpc/zzz__commit.go | 10 +- types/jsonrpc/zzz__event.go | 30 ---- types/jsonrpc/zzz__governance.go | 48 +++++ types/jsonrpc/zzz__peer.go | 58 +++++- types/jsonrpc/zzz__raft.go | 1 + types/jsonrpc/zzz__receipt.go | 142 +++++++++++++++ types/jsonrpc/zzz__tx.go | 49 +++++ .../{base58addr_test.go => zzz__tx_test.go} | 47 +---- 27 files changed, 508 insertions(+), 407 deletions(-) delete mode 100644 types/jsonrpc/base58addr.go delete mode 100644 types/jsonrpc/convChaininfo.go delete mode 100644 types/jsonrpc/convTx_test.go create mode 100644 types/jsonrpc/zzz__block_test.go delete mode 100644 types/jsonrpc/zzz__chainstatus.go delete mode 100644 types/jsonrpc/zzz__event.go create mode 100644 types/jsonrpc/zzz__governance.go create mode 100644 types/jsonrpc/zzz__raft.go create mode 100644 types/jsonrpc/zzz__receipt.go rename types/jsonrpc/{base58addr_test.go => zzz__tx_test.go} (63%) diff --git a/cmd/aergocli/cmd/chaininfo.go b/cmd/aergocli/cmd/chaininfo.go index 112da2158..5f7b3470b 100644 --- a/cmd/aergocli/cmd/chaininfo.go +++ b/cmd/aergocli/cmd/chaininfo.go @@ -21,6 +21,7 @@ var chaininfoCmd = &cobra.Command{ cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(jsonrpc.ConvChainInfoMsg(msg)) + res := jsonrpc.ConvChainInfo(msg) + cmd.Println(jsonrpc.B58JSON(res)) }, } diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 1fb28ff21..8615de490 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -342,7 +342,8 @@ func runCallCmd(cmd *cobra.Command, args []string) error { } if toJSON { - cmd.Println(jsonrpc.TxConvBase58Addr(tx)) + res := jsonrpc.ConvTx(tx, jsonrpc.Base58) + cmd.Println(jsonrpc.B58JSON(res)) } else { txs := []*types.Tx{tx} var msgs *types.CommitResultList @@ -367,7 +368,8 @@ func runGetABICmd(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to get abi: %v", err.Error()) } - cmd.Println(jsonrpc.JSON(abi)) + res := jsonrpc.ConvAbi(abi) + cmd.Println(jsonrpc.B58JSON(res)) return nil } diff --git a/cmd/aergocli/cmd/getblock.go b/cmd/aergocli/cmd/getblock.go index 1e5ed3653..5fe452f67 100644 --- a/cmd/aergocli/cmd/getblock.go +++ b/cmd/aergocli/cmd/getblock.go @@ -45,7 +45,8 @@ func streamBlocks(cmd *cobra.Command) error { if err != nil { return fmt.Errorf("failed to receive block: %v", err) } - cmd.Println(jsonrpc.BlockConvBase58Addr(b)) + res := jsonrpc.ConvBlock(b) + cmd.Println(jsonrpc.B58JSON(res)) } } @@ -70,7 +71,8 @@ func getSingleBlock(cmd *cobra.Command) error { if err != nil { return fmt.Errorf("failed to get block: %v", err) } - cmd.Println(jsonrpc.BlockConvBase58Addr(msg)) + res := jsonrpc.ConvBlock(msg) + cmd.Println(jsonrpc.B58JSON(res)) return nil } diff --git a/cmd/aergocli/cmd/getpeers.go b/cmd/aergocli/cmd/getpeers.go index 899055010..f9436a318 100644 --- a/cmd/aergocli/cmd/getpeers.go +++ b/cmd/aergocli/cmd/getpeers.go @@ -59,12 +59,15 @@ func execGetPeers(cmd *cobra.Command, args []string) { // address and peerid should be encoded, respectively sorter.Sort(msg.Peers) if detailed == 0 { - cmd.Println(jsonrpc.PeerListToString(msg)) + res := jsonrpc.ConvPeerList(msg) + cmd.Println(jsonrpc.B58JSON(res)) } else if detailed > 0 { // TODO show long fields - cmd.Println(jsonrpc.LongPeerListToString(msg)) + res := jsonrpc.ConvLongPeerList(msg) + cmd.Println(jsonrpc.B58JSON(res)) } else { - cmd.Println(jsonrpc.ShortPeerListToString(msg)) + res := jsonrpc.ConvShortPeerList(msg) + cmd.Println(jsonrpc.B58JSON(res)) } } diff --git a/cmd/aergocli/cmd/listblocks.go b/cmd/aergocli/cmd/listblocks.go index 684d372a5..369453876 100644 --- a/cmd/aergocli/cmd/listblocks.go +++ b/cmd/aergocli/cmd/listblocks.go @@ -64,5 +64,6 @@ func execListBlockHeaders(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvBlockHeaderList(msg) + cmd.Println(jsonrpc.B58JSON(res)) } diff --git a/cmd/aergocli/cmd/metric.go b/cmd/aergocli/cmd/metric.go index 94670ca76..a9320f0b3 100644 --- a/cmd/aergocli/cmd/metric.go +++ b/cmd/aergocli/cmd/metric.go @@ -40,5 +40,6 @@ func execMetric(cmd *cobra.Command, args []string) { return } // address and peerid should be encoded, respectively - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvMetrics(msg) + cmd.Println(jsonrpc.B58JSON(res)) } diff --git a/cmd/aergocli/cmd/receipt.go b/cmd/aergocli/cmd/receipt.go index 39da36595..fe6f13c7b 100644 --- a/cmd/aergocli/cmd/receipt.go +++ b/cmd/aergocli/cmd/receipt.go @@ -36,7 +36,8 @@ func init() { if err != nil { log.Fatal(err) } - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvReceipt(msg) + cmd.Println(jsonrpc.B58JSON(res)) }, }, ) diff --git a/cmd/aergocli/cmd/signtx.go b/cmd/aergocli/cmd/signtx.go index c02a86660..701485490 100644 --- a/cmd/aergocli/cmd/signtx.go +++ b/cmd/aergocli/cmd/signtx.go @@ -89,7 +89,8 @@ var signCmd = &cobra.Command{ } if nil == err && msg != nil { - cmd.Println(jsonrpc.TxConvBase58Addr(msg)) + res := jsonrpc.ConvTx(msg, jsonrpc.Base58) + cmd.Println(jsonrpc.B58JSON(res)) } else { cmd.Printf("Failed: %s\n", err.Error()) } @@ -117,7 +118,8 @@ var verifyCmd = &cobra.Command{ return } if msg.Tx != nil { - cmd.Println(jsonrpc.TxConvBase58Addr(msg.Tx)) + res := jsonrpc.ConvTx(msg.Tx, jsonrpc.Base58) + cmd.Println(jsonrpc.B58JSON(res)) } else { cmd.Println(msg.Error) } @@ -127,7 +129,8 @@ var verifyCmd = &cobra.Command{ cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(jsonrpc.TxConvBase58Addr(param[0])) + res := jsonrpc.ConvTx(param[0], jsonrpc.Base58) + cmd.Println(jsonrpc.B58JSON(res)) } }, } diff --git a/cmd/aergocli/cmd/vote.go b/cmd/aergocli/cmd/vote.go index 9c667e8e7..163b9cad0 100644 --- a/cmd/aergocli/cmd/vote.go +++ b/cmd/aergocli/cmd/vote.go @@ -136,7 +136,8 @@ func execVoteStat(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s\n", err.Error()) return } - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvInOutAccountVoteInfo(msg) + cmd.Println(jsonrpc.B58JSON(res)) return } else if fflags.Changed("id") == true { msg, err := client.GetVotes(context.Background(), &types.VoteParams{ diff --git a/cmd/colaris/cmd/metric.go b/cmd/colaris/cmd/metric.go index cca89d40e..0cb971423 100644 --- a/cmd/colaris/cmd/metric.go +++ b/cmd/colaris/cmd/metric.go @@ -34,5 +34,6 @@ func execMetric(cmd *cobra.Command, args []string) { return } // address and peerid should be encoded, respectively - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvMetrics(msg) + cmd.Println(jsonrpc.B58JSON(res)) } diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index aa9acc5a8..9c982ca1e 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -6,6 +6,7 @@ package mempool import ( "encoding/binary" + "encoding/json" "math/big" "math/rand" "os" @@ -16,7 +17,6 @@ import ( crypto "github.com/aergoio/aergo/v2/account/key/crypto" "github.com/aergoio/aergo/v2/config" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/btcsuite/btcd/btcec" "github.com/stretchr/testify/assert" ) diff --git a/types/jsonrpc/base58addr.go b/types/jsonrpc/base58addr.go deleted file mode 100644 index 69bcab84a..000000000 --- a/types/jsonrpc/base58addr.go +++ /dev/null @@ -1,170 +0,0 @@ -package jsonrpc - -import ( - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/aergoio/aergo/v2/internal/enc/base58" - "github.com/aergoio/aergo/v2/p2p/p2putil" - "github.com/aergoio/aergo/v2/types" -) - -func FillTxBody(source *InOutTxBody, target *types.TxBody) error { - var err error - if source == nil { - return errors.New("tx body is empty") - } - target.Nonce = source.Nonce - if source.Account != "" { - target.Account, err = types.DecodeAddress(source.Account) - if err != nil { - return err - } - } - if source.Recipient != "" { - target.Recipient, err = types.DecodeAddress(source.Recipient) - if err != nil { - return err - } - } - if source.Amount != "" { - amount, err := ParseUnit(source.Amount) - if err != nil { - return err - } - target.Amount = amount.Bytes() - } - if source.Payload != "" { - target.Payload, err = base58.Decode(source.Payload) - if err != nil { - return err - } - } - target.GasLimit = source.GasLimit - if source.GasPrice != "" { - price, err := ParseUnit(source.GasPrice) - if err != nil { - return err - } - target.GasPrice = price.Bytes() - } - if source.ChainIdHash != "" { - target.ChainIdHash, err = base58.Decode(source.ChainIdHash) - if err != nil { - return err - } - } - if source.Sign != "" { - target.Sign, err = base58.Decode(source.Sign) - if err != nil { - return err - } - } - target.Type = source.Type - return nil -} - -func ParseBase58Tx(jsonTx []byte) ([]*types.Tx, error) { - var inputlist []InOutTx - err := json.Unmarshal([]byte(jsonTx), &inputlist) - if err != nil { - var input InOutTx - err = json.Unmarshal([]byte(jsonTx), &input) - if err != nil { - return nil, err - } - inputlist = append(inputlist, input) - } - txs := make([]*types.Tx, len(inputlist)) - for i, in := range inputlist { - tx := &types.Tx{Body: &types.TxBody{}} - if in.Hash != "" { - tx.Hash, err = base58.Decode(in.Hash) - if err != nil { - return nil, err - } - } - err = FillTxBody(in.Body, tx.Body) - if err != nil { - return nil, err - } - txs[i] = tx - } - - return txs, nil -} - -func ParseBase58TxBody(jsonTx []byte) (*types.TxBody, error) { - body := &types.TxBody{} - in := &InOutTxBody{} - - err := json.Unmarshal(jsonTx, in) - if err != nil { - return nil, err - } - - err = FillTxBody(in, body) - if err != nil { - return nil, err - } - - return body, nil -} - -func ConvPeerLong(p *types.Peer) *LongInOutPeer { - out := &LongInOutPeer{InOutPeer: *ConvPeer(p)} - out.ProducerIDs = make([]string, len(p.Address.ProducerIDs)) - for i, pid := range p.Address.ProducerIDs { - out.ProducerIDs[i] = base58.Encode(pid) - } - if p.Address.Role == types.PeerRole_Agent { - out.Certificates = make([]*InOutCert, len(p.Certificates)) - for i, cert := range p.Certificates { - addrs := []string{} - for _, ad := range cert.AgentAddress { - addrs = append(addrs, string(ad)) - } - out.Certificates[i] = &InOutCert{CertVersion: cert.CertVersion, - ProducerID: base58.Encode(cert.BPID), AgentID: base58.Encode(cert.AgentID), - CreateTime: time.Unix(0, cert.CreateTime), ExpireTime: time.Unix(0, cert.ExpireTime), - Addresses: addrs} - } - } - return out -} - -func BlockConvBase58Addr(b *types.Block) string { - return toString(ConvBlock(b)) -} - -func PeerListToString(p *types.PeerList) string { - peers := []*InOutPeer{} - for _, peer := range p.GetPeers() { - peers = append(peers, ConvPeer(peer)) - } - return toString(peers) -} -func ShortPeerListToString(p *types.PeerList) string { - var peers []string - for _, peer := range p.GetPeers() { - pa := peer.Address - peers = append(peers, fmt.Sprintf("%s;%s/%d;%s;%d", p2putil.ShortForm(types.PeerID(pa.PeerID)), pa.Address, pa.Port, peer.AcceptedRole.String(), peer.Bestblock.BlockNo)) - } - return toString(peers) -} -func LongPeerListToString(p *types.PeerList) string { - peers := []*LongInOutPeer{} - for _, peer := range p.GetPeers() { - peers = append(peers, ConvPeerLong(peer)) - } - return toString(peers) -} -func toString(out interface{}) string { - jsonout, err := json.MarshalIndent(out, "", " ") - if err != nil { - return "" - } - return string(jsonout) -} diff --git a/types/jsonrpc/convChaininfo.go b/types/jsonrpc/convChaininfo.go deleted file mode 100644 index 7a76eb614..000000000 --- a/types/jsonrpc/convChaininfo.go +++ /dev/null @@ -1,40 +0,0 @@ -package jsonrpc - -import ( - "encoding/json" - "math/big" - - "github.com/aergoio/aergo/v2/consensus" - "github.com/aergoio/aergo/v2/types" -) - -func ConvChainInfoMsg(msg *types.ChainInfo) string { - jsonout, err := json.MarshalIndent(convChainInfo(msg), "", " ") - if err != nil { - return "" - } - return string(jsonout) -} - -func convChainInfo(msg *types.ChainInfo) *InOutChainInfo { - out := &InOutChainInfo{} - out.Chainid.Magic = msg.Id.Magic - out.Chainid.Public = msg.Id.Public - out.Chainid.Mainnet = msg.Id.Mainnet - out.Chainid.Consensus = msg.Id.Consensus - out.Chainid.Version = msg.Id.Version - out.BpNumber = msg.BpNumber - out.MaxBlockSize = msg.Maxblocksize - out.MaxTokens = new(big.Int).SetBytes(msg.Maxtokens).String() - - if consensus.IsDposName(msg.Id.Consensus) { - out.StakingMinimum = new(big.Int).SetBytes(msg.Stakingminimum).String() - out.StakingTotal = new(big.Int).SetBytes(msg.Totalstaking).String() - } - - out.GasPrice = new(big.Int).SetBytes(msg.Gasprice).String() - out.NamePrice = new(big.Int).SetBytes(msg.Nameprice).String() - out.TotalVotingPower = new(big.Int).SetBytes(msg.Totalvotingpower).String() - out.VotingReward = new(big.Int).SetBytes(msg.Votingreward).String() - return out -} diff --git a/types/jsonrpc/convTx.go b/types/jsonrpc/convTx.go index 13afa54be..85c6efb34 100644 --- a/types/jsonrpc/convTx.go +++ b/types/jsonrpc/convTx.go @@ -1,7 +1,5 @@ package jsonrpc -import "github.com/aergoio/aergo/v2/types" - type EncodingType int const ( @@ -10,31 +8,13 @@ const ( ) func (b *InOutTxBody) String() string { - return toString(b) + return B58JSON(b) } func (t *InOutTx) String() string { - return toString(t) + return B58JSON(t) } func (t *InOutTxInBlock) String() string { - return toString(t) -} - -func TxConvBase58Addr(tx *types.Tx) string { - return toString(ConvTx(tx, Base58)) -} - -func TxConvBase58AddrEx(tx *types.Tx, payloadType EncodingType) string { - switch payloadType { - case Raw: - return toString(ConvTx(tx, Raw)) - case Base58: - return toString(ConvTx(tx, Base58)) - } - return "" -} - -func TxInBlockConvBase58Addr(txInBlock *types.TxInBlock) string { - return toString(ConvTxInBlock(txInBlock, Base58)) + return B58JSON(t) } diff --git a/types/jsonrpc/convTx_test.go b/types/jsonrpc/convTx_test.go deleted file mode 100644 index 9be1ca760..000000000 --- a/types/jsonrpc/convTx_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package jsonrpc - -import ( - "testing" - - "github.com/aergoio/aergo/v2/types" - "github.com/stretchr/testify/assert" -) - -func TestConvTxEx(t *testing.T) { - testTx := &types.Tx{Body: &types.TxBody{Payload: []byte("{\"Name\":\"v1createName\",\"Args\":[\"honggildong3\"]}")}} - result := toString(ConvTx(testTx, Base58)) - assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"22MZAFWvxtVWehpgwEVxrvoqGL5xmcPmyLBiwraDfxRwKUNrV9tmhuB7Uu6ZeJWvp\"\n }\n}", result, "") - result = toString(ConvTx(testTx, Raw)) - assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"{\\\"Name\\\":\\\"v1createName\\\",\\\"Args\\\":[\\\"honggildong3\\\"]}\"\n }\n}", result, "") -} diff --git a/types/jsonrpc/zzz__block.go b/types/jsonrpc/zzz__block.go index a5e47ba61..78047ccad 100644 --- a/types/jsonrpc/zzz__block.go +++ b/types/jsonrpc/zzz__block.go @@ -6,8 +6,15 @@ import ( ) func ConvBlock(msg *types.Block) *InOutBlock { + if msg == nil { + return nil + } + b := &InOutBlock{} b.Hash = base58.Encode(msg.Hash) + if bpid, err := msg.BPID(); err == nil { + b.PeerID = bpid.String() + } if msg.Header != nil { b.Header = *ConvBlockHeader(msg.Header) } @@ -19,11 +26,16 @@ func ConvBlock(msg *types.Block) *InOutBlock { type InOutBlock struct { Hash string + PeerID string Header InOutBlockHeader Body InOutBlockBody } func ConvBlockHeader(msg *types.BlockHeader) *InOutBlockHeader { + if msg == nil { + return nil + } + bh := &InOutBlockHeader{} bh.ChainID = base58.Encode(msg.GetChainID()) bh.Version = types.DecodeChainIdVersion(msg.GetChainID()) @@ -62,6 +74,10 @@ type InOutBlockHeader struct { } func ConvBlockBody(msg *types.BlockBody) *InOutBlockBody { + if msg == nil { + return nil + } + bb := &InOutBlockBody{} bb.Txs = make([]*InOutTx, len(msg.Txs)) for i, tx := range msg.Txs { @@ -75,13 +91,34 @@ type InOutBlockBody struct { } func ConvBlockIdx(msg *types.NewBlockNotice) *InOutBlockIdx { - bh := &InOutBlockIdx{} - bh.BlockNo = msg.GetBlockNo() - bh.BlockHash = base58.Encode(msg.GetBlockHash()) - return bh + if msg == nil { + return nil + } + + return &InOutBlockIdx{ + BlockHash: base58.Encode(msg.GetBlockHash()), + BlockNo: msg.GetBlockNo(), + } } type InOutBlockIdx struct { BlockHash string BlockNo uint64 } + +func ConvBlockHeaderList(msg *types.BlockHeaderList) *InOutBlockHeaderList { + if msg == nil { + return nil + } + + b := &InOutBlockHeaderList{} + b.Blocks = make([]*InOutBlock, len(msg.Blocks)) + for i, block := range msg.Blocks { + b.Blocks[i] = ConvBlock(block) + } + return b +} + +type InOutBlockHeaderList struct { + Blocks []*InOutBlock +} diff --git a/types/jsonrpc/zzz__block_test.go b/types/jsonrpc/zzz__block_test.go new file mode 100644 index 000000000..7956d8fc6 --- /dev/null +++ b/types/jsonrpc/zzz__block_test.go @@ -0,0 +1,52 @@ +package jsonrpc + +import ( + "testing" + + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" + "github.com/stretchr/testify/assert" +) + +func TestBlockConv(t *testing.T) { + const accountBase58 = "AmMW2bVcfroiuV4Bvy56op5zzqn42xgrLCwSxMka23K75yTBmudz" + const recipientBase58 = "AmMW2bVcfroiuV4Bvy56op5zzqn42xgrLCwSxMka23K75yTBmudz" + const payloadBase58 = "525mQMtsWaDLVJbzQZgTFkSG33gtZsho7m4io1HUCeJi" + + account, err := types.DecodeAddress(accountBase58) + assert.NoError(t, err, "should be decode account") + + testBlock := &types.Block{ + Header: &types.BlockHeader{ + CoinbaseAccount: account, + }, + Body: &types.BlockBody{ + Txs: []*types.Tx{}, + }, + } + result := ConvBlock(nil) + assert.Empty(t, result, "failed to convert nil") + + result = ConvBlock(testBlock) + assert.Empty(t, result.Body.Txs, "failed to convert txs") + assert.Equal(t, accountBase58, result.Header.CoinbaseAccount, "failed to convert coinbase account") + + recipient, err := types.DecodeAddress(recipientBase58) + assert.NoError(t, err, "should be decode recipient") + + payload, err := base58.Decode(payloadBase58) + assert.NoError(t, err, "should be decode payload") + + testTx := &types.Tx{Body: &types.TxBody{ + Account: account, + Recipient: recipient, + Payload: payload, + }} + + testBlock.Body.Txs = append(testBlock.Body.Txs, testTx) + result = ConvBlock(testBlock) + assert.Equal(t, accountBase58, result.Body.Txs[0].Body.Account, "failed to convert account") + assert.Equal(t, recipientBase58, result.Body.Txs[0].Body.Recipient, "failed to convert recipient") + assert.Equal(t, payloadBase58, result.Body.Txs[0].Body.Payload, "failed to convert payload") + t.Log(ConvBlock(testBlock)) +} diff --git a/types/jsonrpc/zzz__chainInfo.go b/types/jsonrpc/zzz__chainInfo.go index 1bf27dc47..031828a96 100644 --- a/types/jsonrpc/zzz__chainInfo.go +++ b/types/jsonrpc/zzz__chainInfo.go @@ -1,9 +1,12 @@ package jsonrpc import ( + "encoding/json" "math/big" "github.com/aergoio/aergo/v2/consensus" + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/internal/enc/hex" "github.com/aergoio/aergo/v2/types" ) @@ -38,13 +41,13 @@ type InOutChainInfo struct { } func ConvChainId(msg *types.ChainId) *InOutChainId { - ci := &InOutChainId{} - ci.Magic = msg.Magic - ci.Public = msg.Public - ci.Mainnet = msg.Mainnet - ci.Consensus = msg.Consensus - ci.Version = msg.Version - return ci + return &InOutChainId{ + Magic: msg.Magic, + Public: msg.Public, + Mainnet: msg.Mainnet, + Consensus: msg.Consensus, + Version: msg.Version, + } } type InOutChainId struct { @@ -54,3 +57,71 @@ type InOutChainId struct { Consensus string Version int32 } + +func ConvBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { + bs := &InOutBlockchainStatus{} + bs.Hash = base58.Encode(msg.BestBlockHash) + bs.Height = msg.BestHeight + bs.ChainIdHash = base58.Encode(msg.BestChainIdHash) + + toJRM := func(s string) *json.RawMessage { + if len(s) > 0 { + m := json.RawMessage(s) + return &m + } + return nil + } + bs.ConsensusInfo = toJRM(msg.ConsensusInfo) + if msg.ChainInfo != nil { + bs.ChainInfo = ConvChainInfo(msg.ChainInfo) + } + return bs +} + +func ConvHexBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { + bs := &InOutBlockchainStatus{} + bs.Hash = hex.Encode(msg.BestBlockHash) + bs.Height = msg.BestHeight + bs.ChainIdHash = hex.Encode(msg.BestChainIdHash) + return bs +} + +type InOutBlockchainStatus struct { + Hash string + Height uint64 + ConsensusInfo *json.RawMessage `json:",omitempty"` + ChainIdHash string + ChainStat *json.RawMessage `json:",omitempty"` + ChainInfo *InOutChainInfo `json:",omitempty"` +} + +func ConvMetrics(msg *types.Metrics) *InOutMetrics { + m := &InOutMetrics{} + m.Peers = make([]*InOutPeerMetric, len(msg.Peers)) + for i, peer := range msg.Peers { + m.Peers[i] = ConvPeerMetric(peer) + } + return m +} + +type InOutMetrics struct { + Peers []*InOutPeerMetric +} + +func ConvPeerMetric(msg *types.PeerMetric) *InOutPeerMetric { + return &InOutPeerMetric{ + PeerID: base58.Encode(msg.PeerID), + SumIn: msg.SumIn, + AvrIn: msg.AvrIn, + SumOut: msg.SumOut, + AvrOut: msg.AvrOut, + } +} + +type InOutPeerMetric struct { + PeerID string + SumIn int64 `json:",omitempty"` + AvrIn int64 `json:",omitempty"` + SumOut int64 `json:",omitempty"` + AvrOut int64 `json:",omitempty"` +} diff --git a/types/jsonrpc/zzz__chainstatus.go b/types/jsonrpc/zzz__chainstatus.go deleted file mode 100644 index cfff9d257..000000000 --- a/types/jsonrpc/zzz__chainstatus.go +++ /dev/null @@ -1,46 +0,0 @@ -package jsonrpc - -import ( - "encoding/json" - - "github.com/aergoio/aergo/v2/internal/enc/base58" - "github.com/aergoio/aergo/v2/internal/enc/hex" - "github.com/aergoio/aergo/v2/types" -) - -func ConvBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { - bs := &InOutBlockchainStatus{} - bs.Hash = base58.Encode(msg.BestBlockHash) - bs.Height = msg.BestHeight - bs.ChainIdHash = base58.Encode(msg.BestChainIdHash) - - toJRM := func(s string) *json.RawMessage { - if len(s) > 0 { - m := json.RawMessage(s) - return &m - } - return nil - } - bs.ConsensusInfo = toJRM(msg.ConsensusInfo) - if msg.ChainInfo != nil { - bs.ChainInfo = ConvChainInfo(msg.ChainInfo) - } - return bs -} - -func ConvHexBlockchainStatus(msg *types.BlockchainStatus) *InOutBlockchainStatus { - bs := &InOutBlockchainStatus{} - bs.Hash = hex.Encode(msg.BestBlockHash) - bs.Height = msg.BestHeight - bs.ChainIdHash = hex.Encode(msg.BestChainIdHash) - return bs -} - -type InOutBlockchainStatus struct { - Hash string - Height uint64 - ConsensusInfo *json.RawMessage `json:",omitempty"` - ChainIdHash string - ChainStat *json.RawMessage `json:",omitempty"` - ChainInfo *InOutChainInfo `json:",omitempty"` -} diff --git a/types/jsonrpc/zzz__commit.go b/types/jsonrpc/zzz__commit.go index c3002da3c..cce20e505 100644 --- a/types/jsonrpc/zzz__commit.go +++ b/types/jsonrpc/zzz__commit.go @@ -19,11 +19,11 @@ type InOutCommitResultList struct { } func ConvCommitResult(msg *types.CommitResult) *InOutCommitResult { - c := &InOutCommitResult{} - c.Hash = base58.Encode(msg.Hash) - c.Error = msg.Error - c.Detail = msg.Detail - return c + return &InOutCommitResult{ + Hash: base58.Encode(msg.Hash), + Error: msg.Error, + Detail: msg.Detail, + } } type InOutCommitResult struct { diff --git a/types/jsonrpc/zzz__event.go b/types/jsonrpc/zzz__event.go deleted file mode 100644 index 9f3816398..000000000 --- a/types/jsonrpc/zzz__event.go +++ /dev/null @@ -1,30 +0,0 @@ -package jsonrpc - -import ( - "github.com/aergoio/aergo/v2/internal/enc/base58" - "github.com/aergoio/aergo/v2/types" -) - -func ConvEvent(msg *types.Event) *InOutEvent { - e := &InOutEvent{} - e.ContractAddress = base58.Encode(msg.ContractAddress) - e.EventName = msg.EventName - e.JsonArgs = msg.JsonArgs - e.EventIdx = msg.EventIdx - e.TxHash = base58.Encode(msg.TxHash) - e.BlockHash = base58.Encode(msg.BlockHash) - e.BlockNo = msg.BlockNo - e.TxIndex = msg.TxIndex - return e -} - -type InOutEvent struct { - ContractAddress string - EventName string - JsonArgs string - EventIdx int32 - TxHash string - BlockHash string - BlockNo uint64 - TxIndex int32 -} diff --git a/types/jsonrpc/zzz__governance.go b/types/jsonrpc/zzz__governance.go new file mode 100644 index 000000000..265e09d0b --- /dev/null +++ b/types/jsonrpc/zzz__governance.go @@ -0,0 +1,48 @@ +package jsonrpc + +import ( + "math/big" + + "github.com/aergoio/aergo/v2/types" +) + +func ConvInOutAccountVoteInfo(msg *types.AccountVoteInfo) *InOutAccountVoteInfo { + avi := &InOutAccountVoteInfo{} + avi.Staking = *ConvStaking(msg.Staking) + avi.Voting = make([]*InOutVoteInfo, len(msg.Voting)) + for i, v := range msg.Voting { + avi.Voting[i] = ConvVoteInfo(v) + } + return avi +} + +type InOutAccountVoteInfo struct { + Staking InOutStaking + Voting []*InOutVoteInfo +} + +func ConvStaking(msg *types.Staking) *InOutStaking { + return &InOutStaking{ + Amount: new(big.Int).SetBytes(msg.Amount).String(), + When: msg.When, + } +} + +type InOutStaking struct { + Amount string + When uint64 +} + +func ConvVoteInfo(msg *types.VoteInfo) *InOutVoteInfo { + return &InOutVoteInfo{ + Id: msg.Id, + Candidates: msg.Candidates, + Amount: msg.Amount, + } +} + +type InOutVoteInfo struct { + Id string + Candidates []string + Amount string +} diff --git a/types/jsonrpc/zzz__peer.go b/types/jsonrpc/zzz__peer.go index d6ca1fe5b..f147fd31c 100644 --- a/types/jsonrpc/zzz__peer.go +++ b/types/jsonrpc/zzz__peer.go @@ -1,13 +1,28 @@ package jsonrpc import ( + "fmt" "strconv" "time" "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/p2p/p2putil" "github.com/aergoio/aergo/v2/types" ) +func ConvPeerList(msg *types.PeerList) *InOutPeerList { + p := &InOutPeerList{} + p.Peers = make([]*InOutPeer, len(msg.Peers)) + for i, peer := range msg.Peers { + p.Peers[i] = ConvPeer(peer) + } + return p +} + +type InOutPeerList struct { + Peers []*InOutPeer +} + func ConvPeer(msg *types.Peer) *InOutPeer { p := &InOutPeer{} p.Role = msg.AcceptedRole.String() @@ -41,11 +56,11 @@ type InOutPeer struct { } func ConvPeerAddress(msg *types.PeerAddress) *InOutPeerAddress { - pa := &InOutPeerAddress{} - pa.Address = msg.GetAddress() - pa.Port = strconv.Itoa(int(msg.GetPort())) - pa.PeerId = base58.Encode(msg.GetPeerID()) - return pa + return &InOutPeerAddress{ + Address: msg.Address, + Port: strconv.Itoa(int(msg.Port)), + PeerId: base58.Encode(msg.PeerID), + } } type InOutPeerAddress struct { @@ -54,8 +69,35 @@ type InOutPeerAddress struct { PeerId string } -func ConvLongPeer(msg *types.Peer) *LongInOutPeer { - p := &LongInOutPeer{} +func ConvShortPeerList(msg *types.PeerList) *InOutShortPeerList { + p := &InOutShortPeerList{} + p.Peers = make([]string, len(msg.Peers)) + for i, peer := range msg.Peers { + pa := peer.Address + p.Peers[i] = fmt.Sprintf("%s;%s/%d;%s;%d", p2putil.ShortForm(types.PeerID(pa.PeerID)), pa.Address, pa.Port, peer.AcceptedRole.String(), peer.Bestblock.BlockNo) + } + return p +} + +type InOutShortPeerList struct { + Peers []string +} + +func ConvLongPeerList(msg *types.PeerList) *InOutLongPeerList { + p := &InOutLongPeerList{} + p.Peers = make([]*InOutLongPeer, len(msg.Peers)) + for i, peer := range msg.Peers { + p.Peers[i] = ConvLongPeer(peer) + } + return p +} + +type InOutLongPeerList struct { + Peers []*InOutLongPeer +} + +func ConvLongPeer(msg *types.Peer) *InOutLongPeer { + p := &InOutLongPeer{} p.InOutPeer = *ConvPeer(msg) p.ProducerIDs = make([]string, len(msg.Address.ProducerIDs)) @@ -73,7 +115,7 @@ func ConvLongPeer(msg *types.Peer) *LongInOutPeer { return p } -type LongInOutPeer struct { +type InOutLongPeer struct { InOutPeer ProducerIDs []string Certificates []*InOutCert diff --git a/types/jsonrpc/zzz__raft.go b/types/jsonrpc/zzz__raft.go new file mode 100644 index 000000000..29a4d6aba --- /dev/null +++ b/types/jsonrpc/zzz__raft.go @@ -0,0 +1 @@ +package jsonrpc diff --git a/types/jsonrpc/zzz__receipt.go b/types/jsonrpc/zzz__receipt.go new file mode 100644 index 000000000..8cf202e36 --- /dev/null +++ b/types/jsonrpc/zzz__receipt.go @@ -0,0 +1,142 @@ +package jsonrpc + +import ( + "math/big" + + "github.com/aergoio/aergo/v2/internal/enc/base58" + "github.com/aergoio/aergo/v2/types" +) + +func ConvReceipt(msg *types.Receipt) *InOutReceipt { + r := &InOutReceipt{} + r.ContractAddress = types.EncodeAddress(msg.ContractAddress) + r.Status = msg.Status + r.Ret = msg.Ret + r.TxHash = base58.Encode(msg.TxHash) + r.FeeUsed = new(big.Int).SetBytes(msg.FeeUsed).String() + r.CumulativeFeeUsed = new(big.Int).SetBytes(msg.CumulativeFeeUsed).String() + r.Bloom = msg.Bloom + if msg.Events != nil { + r.Events = make([]*InOutEvent, len(msg.Events)) + for i, e := range msg.Events { + r.Events[i] = ConvEvent(e) + } + } + r.BlockHash = base58.Encode(msg.BlockHash) + r.BlockNo = msg.BlockNo + r.TxIndex = msg.TxIndex + r.From = types.EncodeAddress(msg.From) + r.To = types.EncodeAddress(msg.To) + r.FeeDelegation = msg.FeeDelegation + r.GasUsed = msg.GasUsed + return r +} + +type InOutReceipt struct { + ContractAddress string + Status string + Ret string + TxHash string + FeeUsed string + CumulativeFeeUsed string `json:",omitempty"` + Bloom []byte `json:",omitempty"` + Events []*InOutEvent `json:",omitempty"` + BlockHash string + BlockNo uint64 + TxIndex int32 + From string + To string + FeeDelegation bool + GasUsed uint64 +} + +func ConvEvent(msg *types.Event) *InOutEvent { + return &InOutEvent{ + ContractAddress: types.EncodeAddress(msg.ContractAddress), + EventName: msg.EventName, + JsonArgs: msg.JsonArgs, + EventIdx: msg.EventIdx, + TxHash: base58.Encode(msg.TxHash), + BlockHash: base58.Encode(msg.BlockHash), + BlockNo: msg.BlockNo, + TxIndex: msg.TxIndex, + } +} + +type InOutEvent struct { + ContractAddress string + EventName string + JsonArgs string + EventIdx int32 + TxHash string + BlockHash string + BlockNo uint64 + TxIndex int32 +} + +func ConvAbi(msg *types.ABI) *InOutAbi { + abi := &InOutAbi{} + abi.Version = msg.Version + abi.Language = msg.Language + abi.Functions = make([]*InOutFunction, len(msg.Functions)) + for i, fn := range msg.Functions { + abi.Functions[i] = ConvFunction(fn) + } + abi.StateVariables = make([]*InOutStateVar, len(msg.StateVariables)) + for i, sv := range msg.StateVariables { + abi.StateVariables[i] = ConvStateVar(sv) + } + return abi +} + +type InOutAbi struct { + Version string + Language string + Functions []*InOutFunction + StateVariables []*InOutStateVar +} + +func ConvFunction(msg *types.Function) *InOutFunction { + fn := &InOutFunction{} + fn.Name = msg.Name + fn.Arguments = make([]*InOutFunctionArgument, len(msg.Arguments)) + for i, arg := range msg.Arguments { + fn.Arguments[i] = ConvFunctionArgument(arg) + } + fn.Payable = msg.Payable + fn.View = msg.View + fn.FeeDelegation = msg.FeeDelegation + return fn +} + +type InOutFunction struct { + Name string + Arguments []*InOutFunctionArgument + Payable bool + View bool + FeeDelegation bool +} + +func ConvFunctionArgument(msg *types.FnArgument) *InOutFunctionArgument { + return &InOutFunctionArgument{ + Name: msg.Name, + } +} + +type InOutFunctionArgument struct { + Name string +} + +func ConvStateVar(msg *types.StateVar) *InOutStateVar { + return &InOutStateVar{ + Name: msg.Name, + Type: msg.Type, + Len: msg.Len, + } +} + +type InOutStateVar struct { + Name string + Type string + Len int32 +} diff --git a/types/jsonrpc/zzz__tx.go b/types/jsonrpc/zzz__tx.go index c30004735..17c178572 100644 --- a/types/jsonrpc/zzz__tx.go +++ b/types/jsonrpc/zzz__tx.go @@ -1,6 +1,7 @@ package jsonrpc import ( + "encoding/json" "errors" "math/big" @@ -8,6 +9,54 @@ import ( "github.com/aergoio/aergo/v2/types" ) +func ParseBase58Tx(jsonTx []byte) ([]*types.Tx, error) { + var inputlist []InOutTx + err := json.Unmarshal([]byte(jsonTx), &inputlist) + if err != nil { + var input InOutTx + err = json.Unmarshal([]byte(jsonTx), &input) + if err != nil { + return nil, err + } + inputlist = append(inputlist, input) + } + txs := make([]*types.Tx, len(inputlist)) + for i, in := range inputlist { + tx := &types.Tx{Body: &types.TxBody{}} + if in.Hash != "" { + tx.Hash, err = base58.Decode(in.Hash) + if err != nil { + return nil, err + } + } + tx.Body, err = ParseTxBody(in.Body) + if err != nil { + return nil, err + } + txs[i] = tx + } + + return txs, nil +} + +func ParseBase58TxBody(jsonTx []byte) (*types.TxBody, error) { + in := &InOutTxBody{} + err := json.Unmarshal(jsonTx, in) + if err != nil { + return nil, err + } + + body, err := ParseTxBody(in) + if err != nil { + return nil, err + } + + return body, nil +} + +//-----------------------------------------------------------------------// +// + func ConvTx(msg *types.Tx, payloadType EncodingType) (tx *InOutTx) { tx = &InOutTx{} tx.Body = &InOutTxBody{} diff --git a/types/jsonrpc/base58addr_test.go b/types/jsonrpc/zzz__tx_test.go similarity index 63% rename from types/jsonrpc/base58addr_test.go rename to types/jsonrpc/zzz__tx_test.go index 5b9c97253..444000f89 100644 --- a/types/jsonrpc/base58addr_test.go +++ b/types/jsonrpc/zzz__tx_test.go @@ -42,45 +42,10 @@ func TestParseBase58TxBody(t *testing.T) { assert.Equal(t, recipient, res.Recipient, "wrong recipient") } -func TestBlockConvBase58(t *testing.T) { - const accountBase58 = "AmMW2bVcfroiuV4Bvy56op5zzqn42xgrLCwSxMka23K75yTBmudz" - const recipientBase58 = "AmMW2bVcfroiuV4Bvy56op5zzqn42xgrLCwSxMka23K75yTBmudz" - const payloadBase58 = "525mQMtsWaDLVJbzQZgTFkSG33gtZsho7m4io1HUCeJi" - - account, err := types.DecodeAddress(accountBase58) - assert.NoError(t, err, "should be decode account") - - testBlock := &types.Block{ - Header: &types.BlockHeader{ - CoinbaseAccount: account, - }, - Body: &types.BlockBody{ - Txs: []*types.Tx{}, - }, - } - result := ConvBlock(nil) - assert.Empty(t, result, "failed to convert nil") - - result = ConvBlock(testBlock) - assert.Empty(t, result.Body.Txs, "failed to convert txs") - assert.Equal(t, accountBase58, result.Header.CoinbaseAccount, "failed to convert coinbase account") - - recipient, err := types.DecodeAddress(recipientBase58) - assert.NoError(t, err, "should be decode recipient") - - payload, err := base58.Decode(payloadBase58) - assert.NoError(t, err, "should be decode payload") - - testTx := &types.Tx{Body: &types.TxBody{ - Account: account, - Recipient: recipient, - Payload: payload, - }} - - testBlock.Body.Txs = append(testBlock.Body.Txs, testTx) - result = ConvBlock(testBlock) - assert.Equal(t, accountBase58, result.Body.Txs[0].Body.Account, "failed to convert account") - assert.Equal(t, recipientBase58, result.Body.Txs[0].Body.Recipient, "failed to convert recipient") - assert.Equal(t, payloadBase58, result.Body.Txs[0].Body.Payload, "failed to convert payload") - t.Log(BlockConvBase58Addr(testBlock)) +func TestConvTx(t *testing.T) { + testTx := &types.Tx{Body: &types.TxBody{Payload: []byte("{\"Name\":\"v1createName\",\"Args\":[\"honggildong3\"]}")}} + result := B58JSON(ConvTx(testTx, Base58)) + assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"22MZAFWvxtVWehpgwEVxrvoqGL5xmcPmyLBiwraDfxRwKUNrV9tmhuB7Uu6ZeJWvp\"\n }\n}", result, "") + result = B58JSON(ConvTx(testTx, Raw)) + assert.Equal(t, "{\n \"Body\": {\n \"Payload\": \"{\\\"Name\\\":\\\"v1createName\\\",\\\"Args\\\":[\\\"honggildong3\\\"]}\"\n }\n}", result, "") } From d21bae6d8099246a503ac303919e16512b6bb59a Mon Sep 17 00:00:00 2001 From: kch Date: Fri, 17 Nov 2023 04:57:36 +0000 Subject: [PATCH 024/134] remove jsonrpc/encoding/json --- cmd/aergocli/cmd/blockchain.go | 6 +- cmd/aergocli/cmd/blockchain_test.go | 2 +- cmd/aergocli/cmd/chaininfo.go | 2 +- cmd/aergocli/cmd/committx.go | 2 +- cmd/aergocli/cmd/committx_test.go | 9 +- cmd/aergocli/cmd/contract.go | 6 +- cmd/aergocli/cmd/enterprise.go | 14 +- cmd/aergocli/cmd/event.go | 4 +- cmd/aergocli/cmd/getblock.go | 4 +- cmd/aergocli/cmd/getpeers.go | 6 +- cmd/aergocli/cmd/listblocks.go | 2 +- cmd/aergocli/cmd/metric.go | 2 +- cmd/aergocli/cmd/receipt.go | 2 +- cmd/aergocli/cmd/sendtx.go | 4 +- cmd/aergocli/cmd/sendtx_test.go | 7 +- cmd/aergocli/cmd/signtx.go | 6 +- cmd/aergocli/cmd/signtx_test.go | 2 +- cmd/aergocli/cmd/vote.go | 2 +- cmd/colaris/cmd/blacklist.go | 4 +- cmd/colaris/cmd/common.go | 12 - cmd/colaris/cmd/current.go | 2 +- cmd/colaris/cmd/metric.go | 2 +- consensus/impl/raftv2/cluster.go | 4 +- rpc/web3/v1.go | 2 +- types/blockchain.go | 22 +- types/jsonrpc/convTx.go | 20 - types/jsonrpc/{json.go => encoding.go} | 11 +- types/jsonrpc/encoding/encoding.go | 48 - types/jsonrpc/encoding/json/decode.go | 1289 ---------- types/jsonrpc/encoding/json/decode_test.go | 2271 ----------------- types/jsonrpc/encoding/json/encode.go | 1253 --------- types/jsonrpc/encoding/json/encode_test.go | 1027 -------- .../encoding/json/example_marshaling_test.go | 73 - types/jsonrpc/encoding/json/example_test.go | 294 --- types/jsonrpc/encoding/json/fold.go | 144 -- types/jsonrpc/encoding/json/fold_test.go | 116 - types/jsonrpc/encoding/json/indent.go | 141 - types/jsonrpc/encoding/json/number_test.go | 133 - types/jsonrpc/encoding/json/scanner.go | 573 ----- types/jsonrpc/encoding/json/scanner_test.go | 300 --- types/jsonrpc/encoding/json/stream.go | 504 ---- types/jsonrpc/encoding/json/stream_test.go | 439 ---- types/jsonrpc/encoding/json/tables.go | 218 -- types/jsonrpc/encoding/json/tagkey_test.go | 120 - types/jsonrpc/encoding/json/tags.go | 44 - types/jsonrpc/encoding/json/tags_test.go | 28 - .../encoding/json/testdata/code.json.gz | Bin 120432 -> 0 bytes types/jsonrpc/zzz__block.go | 8 +- types/jsonrpc/zzz__enterprise.go | 61 + types/jsonrpc/zzz__polarrpc.go | 15 + types/jsonrpc/zzz__raft.go | 21 + types/jsonrpc/zzz__tx.go | 12 + types/jsonrpc/zzz__tx_test.go | 4 +- 53 files changed, 186 insertions(+), 9111 deletions(-) delete mode 100644 types/jsonrpc/convTx.go rename types/jsonrpc/{json.go => encoding.go} (75%) delete mode 100644 types/jsonrpc/encoding/encoding.go delete mode 100644 types/jsonrpc/encoding/json/decode.go delete mode 100644 types/jsonrpc/encoding/json/decode_test.go delete mode 100644 types/jsonrpc/encoding/json/encode.go delete mode 100644 types/jsonrpc/encoding/json/encode_test.go delete mode 100644 types/jsonrpc/encoding/json/example_marshaling_test.go delete mode 100644 types/jsonrpc/encoding/json/example_test.go delete mode 100644 types/jsonrpc/encoding/json/fold.go delete mode 100644 types/jsonrpc/encoding/json/fold_test.go delete mode 100644 types/jsonrpc/encoding/json/indent.go delete mode 100644 types/jsonrpc/encoding/json/number_test.go delete mode 100644 types/jsonrpc/encoding/json/scanner.go delete mode 100644 types/jsonrpc/encoding/json/scanner_test.go delete mode 100644 types/jsonrpc/encoding/json/stream.go delete mode 100644 types/jsonrpc/encoding/json/stream_test.go delete mode 100644 types/jsonrpc/encoding/json/tables.go delete mode 100644 types/jsonrpc/encoding/json/tagkey_test.go delete mode 100644 types/jsonrpc/encoding/json/tags.go delete mode 100644 types/jsonrpc/encoding/json/tags_test.go delete mode 100644 types/jsonrpc/encoding/json/testdata/code.json.gz create mode 100644 types/jsonrpc/zzz__enterprise.go create mode 100644 types/jsonrpc/zzz__polarrpc.go diff --git a/cmd/aergocli/cmd/blockchain.go b/cmd/aergocli/cmd/blockchain.go index b5bc476bd..dd2bb0855 100644 --- a/cmd/aergocli/cmd/blockchain.go +++ b/cmd/aergocli/cmd/blockchain.go @@ -30,9 +30,11 @@ var blockchainCmd = &cobra.Command{ return } if printHex { - cmd.Println(jsonrpc.ConvHexBlockchainStatus(msg)) + res := jsonrpc.ConvHexBlockchainStatus(msg) + cmd.Println(jsonrpc.MarshalJSON(res)) } else { - cmd.Println(jsonrpc.ConvBlockchainStatus(msg)) + res := jsonrpc.ConvBlockchainStatus(msg) + cmd.Println(jsonrpc.MarshalJSON(res)) } }, } diff --git a/cmd/aergocli/cmd/blockchain_test.go b/cmd/aergocli/cmd/blockchain_test.go index 2e2665b97..631fb04cd 100644 --- a/cmd/aergocli/cmd/blockchain_test.go +++ b/cmd/aergocli/cmd/blockchain_test.go @@ -1,12 +1,12 @@ package cmd import ( + "encoding/json" "testing" "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/internal/enc/hex" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" ) diff --git a/cmd/aergocli/cmd/chaininfo.go b/cmd/aergocli/cmd/chaininfo.go index 5f7b3470b..dd95d5f73 100644 --- a/cmd/aergocli/cmd/chaininfo.go +++ b/cmd/aergocli/cmd/chaininfo.go @@ -22,6 +22,6 @@ var chaininfoCmd = &cobra.Command{ return } res := jsonrpc.ConvChainInfo(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) }, } diff --git a/cmd/aergocli/cmd/committx.go b/cmd/aergocli/cmd/committx.go index abdd0eed1..94b382ea4 100644 --- a/cmd/aergocli/cmd/committx.go +++ b/cmd/aergocli/cmd/committx.go @@ -68,7 +68,7 @@ func execCommitTX(cmd *cobra.Command, args []string) error { return errors.New("Failed request to aergo server\n" + err.Error()) } res := jsonrpc.ConvCommitResultList(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } return nil } diff --git a/cmd/aergocli/cmd/committx_test.go b/cmd/aergocli/cmd/committx_test.go index 4427d8b3e..3b3cc2999 100644 --- a/cmd/aergocli/cmd/committx_test.go +++ b/cmd/aergocli/cmd/committx_test.go @@ -1,11 +1,12 @@ package cmd import ( + "encoding/json" "testing" "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" ) @@ -34,10 +35,10 @@ func TestCommitTxWithMock(t *testing.T) { ).MaxTimes(1) output, err = executeCommand(rootCmd, "committx", "--jsontx", "{\"Body\":{}}") - out := &types.CommitResultList{} + out := &jsonrpc.InOutCommitResultList{} err = json.Unmarshal([]byte(output), out) assert.NoError(t, err, "commit output is invalid") - assert.Equal(t, "tx invalid format", out.GetResults()[0].Detail) + assert.Equal(t, "tx invalid format", out.Results[0].Detail) mock.EXPECT().CommitTX( gomock.Any(), // expect any value for first parameter @@ -56,5 +57,5 @@ func TestCommitTxWithMock(t *testing.T) { output, err = executeCommand(rootCmd, "committx", "--jsontx", "{ \"Hash\": \"HB44gJvHhVoEfgiGq3VZmV9VUXfBXhHjcEvroBMkJGnY\", \"Body\": {\"Nonce\": 2, \"Account\": \"AmNBZ8WQKP8DbuP9Q9W9vGFhiT8vQNcuSZ2SbBbVvbJWGV3Wh1mn\", \"Recipient\": \"AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ\", \"Amount\": \"25000\", \"Payload\": \"\", \"Limit\": 100, \"Price\": \"1\", \"Type\": 0, \"Sign\": \"381yXYxTtq2tRPRQPF7tHH6Cq3y8PvcsFWztPwCRmmYfqnK83Z3a6Yj9fyy8Rpvrrw76Y52SNAP6Th3BYQjX1Bcmf6NQrDHQ\"}}") err = json.Unmarshal([]byte(output), out) assert.NoError(t, err, "should no error") - assert.Equal(t, "HB44gJvHhVoEfgiGq3VZmV9VUXfBXhHjcEvroBMkJGnY", base58.Encode(out.GetResults()[0].Hash)) + assert.Equal(t, "HB44gJvHhVoEfgiGq3VZmV9VUXfBXhHjcEvroBMkJGnY", out.Results[0].Hash) } diff --git a/cmd/aergocli/cmd/contract.go b/cmd/aergocli/cmd/contract.go index 8615de490..9d0b6f4cb 100644 --- a/cmd/aergocli/cmd/contract.go +++ b/cmd/aergocli/cmd/contract.go @@ -343,7 +343,7 @@ func runCallCmd(cmd *cobra.Command, args []string) error { if toJSON { res := jsonrpc.ConvTx(tx, jsonrpc.Base58) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } else { txs := []*types.Tx{tx} var msgs *types.CommitResultList @@ -352,7 +352,7 @@ func runCallCmd(cmd *cobra.Command, args []string) error { return fmt.Errorf("failed to commit tx: %v", err.Error()) } res := jsonrpc.ConvCommitResult(msgs.Results[0]) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } return nil } @@ -369,7 +369,7 @@ func runGetABICmd(cmd *cobra.Command, args []string) error { return fmt.Errorf("failed to get abi: %v", err.Error()) } res := jsonrpc.ConvAbi(abi) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) return nil } diff --git a/cmd/aergocli/cmd/enterprise.go b/cmd/aergocli/cmd/enterprise.go index b010bb08a..fdd5c80f1 100644 --- a/cmd/aergocli/cmd/enterprise.go +++ b/cmd/aergocli/cmd/enterprise.go @@ -8,6 +8,7 @@ package cmd import ( "context" "encoding/binary" + "encoding/json" "errors" "fmt" "strings" @@ -18,7 +19,6 @@ import ( "github.com/aergoio/aergo/v2/types" aergorpc "github.com/aergoio/aergo/v2/types" "github.com/aergoio/aergo/v2/types/jsonrpc" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/spf13/cobra" ) @@ -67,7 +67,7 @@ var enterpriseKeyCmd = &cobra.Command{ if strings.ToUpper(args[0]) != "PERMISSIONS" { out.On = &msg.On //it's for print false } - cmd.Println(jsonrpc.B58JSON(out)) + cmd.Println(jsonrpc.MarshalJSON(out)) }, } @@ -86,7 +86,7 @@ func getConfChangeBlockNo(blockHash []byte) (aergorpc.BlockNo, error) { type OutConfChange struct { Payload string - TxStatus *aergorpc.EnterpriseTxStatus + TxStatus *jsonrpc.InOutEnterpriseTxStatus } func (occ *OutConfChange) ToString() string { @@ -222,21 +222,21 @@ var enterpriseTxCmd = &cobra.Command{ cmd.Println(output.ToString()) return } - output.TxStatus = &aergorpc.EnterpriseTxStatus{ + TxStatus := &aergorpc.EnterpriseTxStatus{ Status: receipt.GetStatus(), Ret: receipt.GetRet(), } if ci.Name == enterprise.ChangeCluster { if confChange, err = getChangeClusterStatus(cmd, msgblock.TxIdx.BlockHash, timer); err != nil { - output.TxStatus.CCStatus = &types.ChangeClusterStatus{Error: err.Error()} + TxStatus.CCStatus = &types.ChangeClusterStatus{Error: err.Error()} } if confChange != nil { - output.TxStatus.CCStatus = confChange.ToPrintable() + TxStatus.CCStatus = confChange.ToPrintable() } } - + output.TxStatus = jsonrpc.ConvEnterpriseTxStatus(TxStatus) cmd.Println(output.ToString()) } diff --git a/cmd/aergocli/cmd/event.go b/cmd/aergocli/cmd/event.go index 207280325..4c50acaac 100644 --- a/cmd/aergocli/cmd/event.go +++ b/cmd/aergocli/cmd/event.go @@ -83,7 +83,7 @@ func execListEvent(cmd *cobra.Command, args []string) { } for _, event := range events.GetEvents() { res := jsonrpc.ConvEvent(event) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } } @@ -110,6 +110,6 @@ func execStreamEvent(cmd *cobra.Command, args []string) { return } res := jsonrpc.ConvEvent(event) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } } diff --git a/cmd/aergocli/cmd/getblock.go b/cmd/aergocli/cmd/getblock.go index 5fe452f67..b3ac3c123 100644 --- a/cmd/aergocli/cmd/getblock.go +++ b/cmd/aergocli/cmd/getblock.go @@ -46,7 +46,7 @@ func streamBlocks(cmd *cobra.Command) error { return fmt.Errorf("failed to receive block: %v", err) } res := jsonrpc.ConvBlock(b) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } } @@ -72,7 +72,7 @@ func getSingleBlock(cmd *cobra.Command) error { return fmt.Errorf("failed to get block: %v", err) } res := jsonrpc.ConvBlock(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) return nil } diff --git a/cmd/aergocli/cmd/getpeers.go b/cmd/aergocli/cmd/getpeers.go index f9436a318..93d490a11 100644 --- a/cmd/aergocli/cmd/getpeers.go +++ b/cmd/aergocli/cmd/getpeers.go @@ -60,14 +60,14 @@ func execGetPeers(cmd *cobra.Command, args []string) { sorter.Sort(msg.Peers) if detailed == 0 { res := jsonrpc.ConvPeerList(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } else if detailed > 0 { // TODO show long fields res := jsonrpc.ConvLongPeerList(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } else { res := jsonrpc.ConvShortPeerList(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } } diff --git a/cmd/aergocli/cmd/listblocks.go b/cmd/aergocli/cmd/listblocks.go index 369453876..e384a5ba6 100644 --- a/cmd/aergocli/cmd/listblocks.go +++ b/cmd/aergocli/cmd/listblocks.go @@ -65,5 +65,5 @@ func execListBlockHeaders(cmd *cobra.Command, args []string) { return } res := jsonrpc.ConvBlockHeaderList(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } diff --git a/cmd/aergocli/cmd/metric.go b/cmd/aergocli/cmd/metric.go index a9320f0b3..40e22a8e6 100644 --- a/cmd/aergocli/cmd/metric.go +++ b/cmd/aergocli/cmd/metric.go @@ -41,5 +41,5 @@ func execMetric(cmd *cobra.Command, args []string) { } // address and peerid should be encoded, respectively res := jsonrpc.ConvMetrics(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } diff --git a/cmd/aergocli/cmd/receipt.go b/cmd/aergocli/cmd/receipt.go index fe6f13c7b..3a033707c 100644 --- a/cmd/aergocli/cmd/receipt.go +++ b/cmd/aergocli/cmd/receipt.go @@ -37,7 +37,7 @@ func init() { log.Fatal(err) } res := jsonrpc.ConvReceipt(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) }, }, ) diff --git a/cmd/aergocli/cmd/sendtx.go b/cmd/aergocli/cmd/sendtx.go index c6ee7d6e4..44fbfcaff 100644 --- a/cmd/aergocli/cmd/sendtx.go +++ b/cmd/aergocli/cmd/sendtx.go @@ -101,13 +101,13 @@ func sendTX(cmd *cobra.Command, tx *types.Tx, account []byte) string { return "Failed request to aergo server: " + err.Error() } res := jsonrpc.ConvCommitResult(msgs.Results[0]) - return jsonrpc.B58JSON(res) + return jsonrpc.MarshalJSON(res) } else { msg, err := client.SendTX(context.Background(), tx) if err != nil { return "Failed request to aergo sever: " + err.Error() } res := jsonrpc.ConvCommitResult(msg) - return jsonrpc.B58JSON(res) + return jsonrpc.MarshalJSON(res) } } diff --git a/cmd/aergocli/cmd/sendtx_test.go b/cmd/aergocli/cmd/sendtx_test.go index 083f53cc3..c5ef7574c 100644 --- a/cmd/aergocli/cmd/sendtx_test.go +++ b/cmd/aergocli/cmd/sendtx_test.go @@ -1,11 +1,12 @@ package cmd import ( + "encoding/json" "testing" "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" + "github.com/aergoio/aergo/v2/types/jsonrpc" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" ) @@ -32,9 +33,9 @@ func TestSendTxWithMock(t *testing.T) { output, err := executeCommand(rootCmd, "sendtx", "--from", "AmNL5neKQS2ZwRuBeqfcfHMLg3aSmGoefEh5bW8ozWxrtmxaGHZ3", "--to", "AmNfacq5A3orqn3MhgkHSncufXEP8gVJgqDy8jTgBphXQeuuaHHF", "--amount", "1000", "--keystore", "") assert.NoError(t, err, "should no error") t.Log(output) - out := &types.CommitResult{} + out := &jsonrpc.InOutCommitResult{} err = json.Unmarshal([]byte(output), out) - assert.Equal(t, testTxHashString, base58.Encode(out.Hash)) + assert.Equal(t, testTxHashString, out.Hash) } func TestSendTxFromToValidation(t *testing.T) { diff --git a/cmd/aergocli/cmd/signtx.go b/cmd/aergocli/cmd/signtx.go index 701485490..86b90bfc8 100644 --- a/cmd/aergocli/cmd/signtx.go +++ b/cmd/aergocli/cmd/signtx.go @@ -90,7 +90,7 @@ var signCmd = &cobra.Command{ if nil == err && msg != nil { res := jsonrpc.ConvTx(msg, jsonrpc.Base58) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } else { cmd.Printf("Failed: %s\n", err.Error()) } @@ -119,7 +119,7 @@ var verifyCmd = &cobra.Command{ } if msg.Tx != nil { res := jsonrpc.ConvTx(msg.Tx, jsonrpc.Base58) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } else { cmd.Println(msg.Error) } @@ -130,7 +130,7 @@ var verifyCmd = &cobra.Command{ return } res := jsonrpc.ConvTx(param[0], jsonrpc.Base58) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } }, } diff --git a/cmd/aergocli/cmd/signtx_test.go b/cmd/aergocli/cmd/signtx_test.go index 2ee039c6f..109a9af38 100644 --- a/cmd/aergocli/cmd/signtx_test.go +++ b/cmd/aergocli/cmd/signtx_test.go @@ -1,6 +1,7 @@ package cmd import ( + "encoding/json" "os" "regexp" "strings" @@ -9,7 +10,6 @@ import ( "github.com/aergoio/aergo/v2/internal/enc/base58" "github.com/aergoio/aergo/v2/types" "github.com/aergoio/aergo/v2/types/jsonrpc" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "github.com/stretchr/testify/assert" ) diff --git a/cmd/aergocli/cmd/vote.go b/cmd/aergocli/cmd/vote.go index 163b9cad0..09957d7c7 100644 --- a/cmd/aergocli/cmd/vote.go +++ b/cmd/aergocli/cmd/vote.go @@ -137,7 +137,7 @@ func execVoteStat(cmd *cobra.Command, args []string) { return } res := jsonrpc.ConvInOutAccountVoteInfo(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) return } else if fflags.Changed("id") == true { msg, err := client.GetVotes(context.Background(), &types.VoteParams{ diff --git a/cmd/colaris/cmd/blacklist.go b/cmd/colaris/cmd/blacklist.go index b0acca4f2..55a79535e 100644 --- a/cmd/colaris/cmd/blacklist.go +++ b/cmd/colaris/cmd/blacklist.go @@ -64,8 +64,8 @@ func listBlacklistEntries(cmd *cobra.Command, args []string) { cmd.Printf("Failed: %s", err.Error()) return } - - cmd.Println(jsonrpc.JSON(msg)) + res := jsonrpc.ConvBLConfEntries(msg) + cmd.Println(jsonrpc.MarshalJSON(res)) } func addBlacklistEntry(cmd *cobra.Command, args []string) { diff --git a/cmd/colaris/cmd/common.go b/cmd/colaris/cmd/common.go index 733d368ea..4bdcf3d55 100644 --- a/cmd/colaris/cmd/common.go +++ b/cmd/colaris/cmd/common.go @@ -8,9 +8,7 @@ package cmd import ( "fmt" - "github.com/aergoio/aergo/v2/internal/enc/proto" "github.com/aergoio/aergo/v2/types" - "github.com/aergoio/aergo/v2/types/jsonrpc/encoding/json" "google.golang.org/grpc" ) @@ -38,13 +36,3 @@ func (c *PolarisClient) Close() { c.conn.Close() c.conn = nil } - -// JSON converts protobuf message(struct) to json notation -func JSON(pb proto.Message) string { - jsonout, err := json.MarshalIndent(pb, "", " ") - if err != nil { - fmt.Printf("Failed: %s\n", err.Error()) - return "" - } - return string(jsonout) -} diff --git a/cmd/colaris/cmd/current.go b/cmd/colaris/cmd/current.go index a35e97bdd..1860422c0 100644 --- a/cmd/colaris/cmd/current.go +++ b/cmd/colaris/cmd/current.go @@ -61,7 +61,7 @@ func execCurrentPeers(cmd *cobra.Command, args []string) { for i, p := range msg.Peers { ppList[i] = NewJSONPolarisPeer(p) } - cmd.Println(jsonrpc.B58JSON(ppList)) + cmd.Println(jsonrpc.MarshalJSON(ppList)) } type PolarisPeerAlias types.PolarisPeer diff --git a/cmd/colaris/cmd/metric.go b/cmd/colaris/cmd/metric.go index 0cb971423..0e9fc33d9 100644 --- a/cmd/colaris/cmd/metric.go +++ b/cmd/colaris/cmd/metric.go @@ -35,5 +35,5 @@ func execMetric(cmd *cobra.Command, args []string) { } // address and peerid should be encoded, respectively res := jsonrpc.ConvMetrics(msg) - cmd.Println(jsonrpc.B58JSON(res)) + cmd.Println(jsonrpc.MarshalJSON(res)) } diff --git a/consensus/impl/raftv2/cluster.go b/consensus/impl/raftv2/cluster.go index c33420729..7d84ae139 100644 --- a/consensus/impl/raftv2/cluster.go +++ b/consensus/impl/raftv2/cluster.go @@ -1009,8 +1009,8 @@ func (cl *Cluster) AfterConfChange(cc *raftpb.ConfChange, member *consensus.Memb } propose := cl.savedChange - - logger.Info().Str("req", jsonrpc.JSON(propose.Cc)).Msg("conf change succeed") + res := jsonrpc.ConvConfChange(propose.Cc) + logger.Info().Str("req", jsonrpc.MarshalJSON(res)).Msg("conf change succeed") cl.resetSavedConfChangePropose() diff --git a/rpc/web3/v1.go b/rpc/web3/v1.go index ab59331f5..cbd1f127c 100644 --- a/rpc/web3/v1.go +++ b/rpc/web3/v1.go @@ -1188,7 +1188,7 @@ func (api *Web3APIv1) GetEnterpriseConfig() (handler http.Handler, ok bool) { out.On = &msg.On } - return stringResponseHandler(jsonrpc.B58JSON(out), nil), true + return stringResponseHandler(jsonrpc.MarshalJSON(out), nil), true } func (api *Web3APIv1) GetConfChangeProgress() (handler http.Handler, ok bool) { diff --git a/types/blockchain.go b/types/blockchain.go index e4905dc54..f3bdb46a9 100644 --- a/types/blockchain.go +++ b/types/blockchain.go @@ -433,16 +433,7 @@ func (block *Block) VerifySign() (valid bool, err error) { // BPID returns its Block Producer's ID from block. func (block *Block) BPID() (id PeerID, err error) { - var pubKey crypto.PubKey - if pubKey, err = crypto.UnmarshalPublicKey(block.Header.PubKey); err != nil { - return PeerID(""), err - } - - if id, err = IDFromPublicKey(pubKey); err != nil { - return PeerID(""), err - } - - return + return block.Header.BPID() } // BpID2Str returns its Block Producer's ID in base64 format. @@ -680,6 +671,17 @@ func (b *BlockHeaderInfo) ChainIdHash() []byte { return common.Hasher(b.ChainId) } +func (bh *BlockHeader) BPID() (id PeerID, err error) { + var pubKey crypto.PubKey + if pubKey, err = crypto.UnmarshalPublicKey(bh.PubKey); err != nil { + return PeerID(""), err + } + if id, err = IDFromPublicKey(pubKey); err != nil { + return PeerID(""), err + } + return +} + // HasFunction returns if a function with the given name exists in the ABI definition func (abi *ABI) HasFunction(name string) bool { for _, fn := range abi.Functions { diff --git a/types/jsonrpc/convTx.go b/types/jsonrpc/convTx.go deleted file mode 100644 index 85c6efb34..000000000 --- a/types/jsonrpc/convTx.go +++ /dev/null @@ -1,20 +0,0 @@ -package jsonrpc - -type EncodingType int - -const ( - Raw EncodingType = 0 + iota - Base58 -) - -func (b *InOutTxBody) String() string { - return B58JSON(b) -} - -func (t *InOutTx) String() string { - return B58JSON(t) -} - -func (t *InOutTxInBlock) String() string { - return B58JSON(t) -} diff --git a/types/jsonrpc/json.go b/types/jsonrpc/encoding.go similarity index 75% rename from types/jsonrpc/json.go rename to types/jsonrpc/encoding.go index 4fad6c03c..c9b66cb53 100644 --- a/types/jsonrpc/json.go +++ b/types/jsonrpc/encoding.go @@ -7,7 +7,14 @@ import ( "github.com/aergoio/aergo/v2/internal/enc/proto" ) -// JSON converts protobuf message(struct) to json notation +type EncodingType int + +const ( + Raw EncodingType = 0 + iota + Base58 +) + +// Deprecated - TODO remove func JSON(pb proto.Message) string { jsonout, err := json.MarshalIndent(pb, "", " ") if err != nil { @@ -17,7 +24,7 @@ func JSON(pb proto.Message) string { return string(jsonout) } -func B58JSON(i interface{}) string { +func MarshalJSON(i interface{}) string { jsonout, err := json.MarshalIndent(i, "", " ") if err != nil { fmt.Printf("Failed: %s\n", err.Error()) diff --git a/types/jsonrpc/encoding/encoding.go b/types/jsonrpc/encoding/encoding.go deleted file mode 100644 index cc5a53699..000000000 --- a/types/jsonrpc/encoding/encoding.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package encoding defines interfaces shared by other packages that -// convert data to and from byte-level and textual representations. -// Packages that check for these interfaces include encoding/gob, -// encoding/json, and encoding/xml. As a result, implementing an -// interface once can make a type useful in multiple encodings. -// Standard types that implement these interfaces include time.Time and net.IP. -// The interfaces come in pairs that produce and consume encoded data. -package encoding - -// BinaryMarshaler is the interface implemented by an object that can -// marshal itself into a binary form. -// -// MarshalBinary encodes the receiver into a binary form and returns the result. -type BinaryMarshaler interface { - MarshalBinary() (data []byte, err error) -} - -// BinaryUnmarshaler is the interface implemented by an object that can -// unmarshal a binary representation of itself. -// -// UnmarshalBinary must be able to decode the form generated by MarshalBinary. -// UnmarshalBinary must copy the data if it wishes to retain the data -// after returning. -type BinaryUnmarshaler interface { - UnmarshalBinary(data []byte) error -} - -// TextMarshaler is the interface implemented by an object that can -// marshal itself into a textual form. -// -// MarshalText encodes the receiver into UTF-8-encoded text and returns the result. -type TextMarshaler interface { - MarshalText() (text []byte, err error) -} - -// TextUnmarshaler is the interface implemented by an object that can -// unmarshal a textual representation of itself. -// -// UnmarshalText must be able to decode the form generated by MarshalText. -// UnmarshalText must copy the text if it wishes to retain the text -// after returning. -type TextUnmarshaler interface { - UnmarshalText(text []byte) error -} diff --git a/types/jsonrpc/encoding/json/decode.go b/types/jsonrpc/encoding/json/decode.go deleted file mode 100644 index a6dd2b0d8..000000000 --- a/types/jsonrpc/encoding/json/decode.go +++ /dev/null @@ -1,1289 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package json - -import ( - "bytes" - "encoding" - "fmt" - "reflect" - "strconv" - "unicode" - "unicode/utf16" - "unicode/utf8" - - "github.com/aergoio/aergo/v2/internal/enc/base58" -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. If v is nil or not a pointer, -// Unmarshal returns an InvalidUnmarshalError. -// -// Unmarshal uses the inverse of the encodings that -// Marshal uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a value implementing the Unmarshaler interface, -// Unmarshal calls that value's UnmarshalJSON method, including -// when the input is a JSON null. -// Otherwise, if the value implements encoding.TextUnmarshaler -// and the input is a JSON quoted string, Unmarshal calls that value's -// UnmarshalText method with the unquoted form of the string. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. By -// default, object keys which don't have a corresponding struct field are -// ignored (see Decoder.DisallowUnknownFields for an alternative). -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -// bool, for JSON booleans -// float64, for JSON numbers -// string, for JSON strings -// []interface{}, for JSON arrays -// map[string]interface{}, for JSON objects -// nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores -// key-value pairs from the JSON object into the map. The map's key type must -// either be a string, an integer, or implement encoding.TextUnmarshaler. -// -// If a JSON value is not appropriate for a given target type, -// or if a JSON number overflows the target type, Unmarshal -// skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an UnmarshalTypeError describing the earliest such error. In any -// case, it's not guaranteed that all the remaining fields following -// the problematic one will be unmarshaled into the target object. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// “not present,” unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -func Unmarshal(data []byte, v interface{}) error { - // Check for well-formedness. - // Avoids filling out half a data structure - // before discovering a JSON syntax error. - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return err - } - - d.init(data) - return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -// -// By convention, to approximate the behavior of Unmarshal itself, -// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. -type Unmarshaler interface { - UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to - Offset int64 // error occurred after reading Offset bytes - Struct string // name of the struct type containing the field - Field string // name of the field holding the Go value -} - -func (e *UnmarshalTypeError) Error() string { - if e.Struct != "" || e.Field != "" { - return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() - } - return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// -// Deprecated: No longer used; kept for compatibility. -type UnmarshalFieldError struct { - Key string - Type reflect.Type - Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { - return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. -// (The argument to Unmarshal must be a non-nil pointer.) -type InvalidUnmarshalError struct { - Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { - if e.Type == nil { - return "json: Unmarshal(nil)" - } - - if e.Type.Kind() != reflect.Ptr { - return "json: Unmarshal(non-pointer " + e.Type.String() + ")" - } - return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v interface{}) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - return &InvalidUnmarshalError{reflect.TypeOf(v)} - } - - d.scan.reset() - d.scanWhile(scanSkipSpace) - // We decode rv not rv.Elem because the Unmarshaler interface - // test must be applied at the top level of the value. - err := d.value(rv) - if err != nil { - return d.addErrorContext(err) - } - return d.savedError -} - -// A Number represents a JSON number literal. -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -// isValidNumber reports whether s is a valid JSON number literal. -func isValidNumber(s string) bool { - // This function implements the JSON numbers grammar. - // See https://tools.ietf.org/html/rfc7159#section-6 - // and https://json.org/number.gif - - if s == "" { - return false - } - - // Optional - - if s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - - // Digits - switch { - default: - return false - - case s[0] == '0': - s = s[1:] - - case '1' <= s[0] && s[0] <= '9': - s = s[1:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // . followed by 1 or more digits. - if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { - s = s[2:] - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // e or E followed by an optional - or + and - // 1 or more digits. - if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { - s = s[1:] - if s[0] == '+' || s[0] == '-' { - s = s[1:] - if s == "" { - return false - } - } - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - s = s[1:] - } - } - - // Make sure we are at the end. - return s == "" -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - Field string - } - savedError error - useNumber bool - disallowUnknownFields bool -} - -// readIndex returns the position of the last byte read. -func (d *decodeState) readIndex() int { - return d.off - 1 -} - -// phasePanicMsg is used as a panic message when we end up with something that -// shouldn't happen. It can indicate a bug in the JSON decoder, or that -// something is editing the data slice while the decoder executes. -const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - d.savedError = nil - d.errorContext.Struct = nil - d.errorContext.Field = "" - return d -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { - if d.savedError == nil { - d.savedError = d.addErrorContext(err) - } -} - -// addErrorContext returns a new error enhanced with information from d.errorContext -func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || d.errorContext.Field != "" { - switch err := err.(type) { - case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct.Name() - err.Field = d.errorContext.Field - return err - } - } - return err -} - -// skip scans to the end of what was started. -func (d *decodeState) skip() { - s, data, i := &d.scan, d.data, d.off - depth := len(s.parseState) - for { - op := s.step(s, data[i]) - i++ - if len(s.parseState) < depth { - d.off = i - d.opcode = op - return - } - } -} - -// scanNext processes the byte at d.data[d.off]. -func (d *decodeState) scanNext() { - if d.off < len(d.data) { - d.opcode = d.scan.step(&d.scan, d.data[d.off]) - d.off++ - } else { - d.opcode = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -func (d *decodeState) scanWhile(op int) { - s, data, i := &d.scan, d.data, d.off - for i < len(data) { - newOp := s.step(s, data[i]) - i++ - if newOp != op { - d.opcode = newOp - d.off = i - return - } - } - - d.off = len(data) + 1 // mark processed EOF with len+1 - d.opcode = d.scan.eof() -} - -// value consumes a JSON value from d.data[d.off-1:], decoding into v, and -// reads the following byte ahead. If v is invalid, the value is discarded. -// The first byte of the value has been read already. -func (d *decodeState) value(v reflect.Value) error { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray: - if v.IsValid() { - if err := d.array(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginObject: - if v.IsValid() { - if err := d.object(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginLiteral: - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.scanWhile(scanContinue) - - if v.IsValid() { - if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { - return err - } - } - } - return nil -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() interface{} { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray, scanBeginObject: - d.skip() - d.scanNext() - - case scanBeginLiteral: - v := d.literalInterface() - switch v.(type) { - case nil, string: - return v - } - } - return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// if it encounters an Unmarshaler, indirect stops and returns that. -// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // Issue #24153 indicates that it is generally not a guaranteed property - // that you may round-trip a reflect.Value by calling Value.Addr().Elem() - // and expect the value to still be settable for values derived from - // unexported embedded struct fields. - // - // The logic below effectively does this when it first addresses the value - // (to satisfy possible pointer methods) and continues to dereference - // subsequent pointers as necessary. - // - // After the first round-trip, we set v back to the original value to - // preserve the original RW flags contained in reflect.Value. - v0 := v - haveAddr := false - - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { - haveAddr = true - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - haveAddr = false - v = e - continue - } - } - - if v.Kind() != reflect.Ptr { - break - } - - if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { - break - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - if v.Type().NumMethod() > 0 { - if u, ok := v.Interface().(Unmarshaler); ok { - return u, nil, reflect.Value{} - } - if !decodingNull { - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, reflect.Value{} - } - } - } - - if haveAddr { - v = v0 // restore original value after round-trip Value.Addr().Elem() - haveAddr = false - } else { - v = v.Elem() - } - } - return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into v. -// The first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - - // Check type of target. - switch v.Kind() { - case reflect.Interface: - if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. - ai := d.arrayInterface() - v.Set(reflect.ValueOf(ai)) - return nil - } - // Otherwise it's invalid. - fallthrough - default: - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - case reflect.Array, reflect.Slice: - break - } - - i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - // Get element of array, growing if necessary. - if v.Kind() == reflect.Slice { - // Grow slice if necessary - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 - } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - } - - if i < v.Len() { - // Decode into element. - if err := d.value(v.Index(i)); err != nil { - return err - } - } else { - // Ran out of fixed array: skip. - if err := d.value(reflect.Value{}); err != nil { - return err - } - } - i++ - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - - if i < v.Len() { - if v.Kind() == reflect.Array { - // Array. Zero the rest. - z := reflect.Zero(v.Type().Elem()) - for ; i < v.Len(); i++ { - v.Index(i).Set(z) - } - } else { - v.SetLen(i) - } - } - if i == 0 && v.Kind() == reflect.Slice { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } - return nil -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - -// object consumes an object from d.data[d.off-1:], decoding into v. -// The first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - t := v.Type() - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - oi := d.objectInterface() - v.Set(reflect.ValueOf(oi)) - return nil - } - - var fields []field - - // Check type of target: - // struct or - // map[T1]T2 where T1 is string, an integer type, - // or an encoding.TextUnmarshaler - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind, have an integer kind, - // or be an encoding.TextUnmarshaler. - switch t.Key().Kind() { - case reflect.String, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - default: - if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - fields = cachedTypeFields(t) - // ok - default: - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - - var mapElem reflect.Value - originalErrorContext := d.errorContext - - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read key. - start := d.readIndex() - d.scanWhile(scanContinue) - item := d.data[start:d.readIndex()] - key, ok := unquoteBytes(item) - if !ok { - panic(phasePanicMsg) - } - - // Figure out field corresponding to key. - var subv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := t.Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } - subv = mapElem - } else { - var f *field - for i := range fields { - ff := &fields[i] - if bytes.Equal(ff.nameBytes, key) { - f = ff - break - } - if f == nil && ff.equalFold(ff.nameBytes, key) { - f = ff - } - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Ptr { - if subv.IsNil() { - // If a struct embeds a pointer to an unexported type, - // it is not possible to set a newly allocated value - // since the field is unexported. - // - // See https://golang.org/issue/21357 - if !subv.CanSet() { - d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) - // Invalidate subv to ensure d.value(subv) skips over - // the JSON value without assigning it to subv. - subv = reflect.Value{} - destring = false - break - } - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - d.errorContext.Field = f.name - d.errorContext.Struct = t - } else if d.disallowUnknownFields { - d.saveError(fmt.Errorf("json: unknown field %q", key)) - } - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - if err := d.literalStore(nullLiteral, subv, false); err != nil { - return err - } - case string: - if err := d.literalStore([]byte(qv), subv, true); err != nil { - return err - } - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - if err := d.value(subv); err != nil { - return err - } - } - - // Write value back to map; - // if using struct, subv points into struct already. - if v.Kind() == reflect.Map { - kt := t.Key() - var kv reflect.Value - switch { - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(kt) - case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(kt) - if err := d.literalStore(item, kv, true); err != nil { - return err - } - kv = kv.Elem() - default: - switch kt.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := string(key) - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - return nil - } - kv = reflect.ValueOf(n).Convert(kt) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - s := string(key) - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - return nil - } - kv = reflect.ValueOf(n).Convert(kt) - default: - panic("json: Unexpected key type") // should never occur - } - } - v.SetMapIndex(kv, subv) - } - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - - d.errorContext = originalErrorContext - } - return nil -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (interface{}, error) { - if d.useNumber { - return Number(s), nil - } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} - } - return f, nil -} - -var numberType = reflect.TypeOf(Number("")) - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { - // Check for unmarshaler. - if len(item) == 0 { - //Empty string given - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - isNull := item[0] == 'n' // null - u, ut, pv := indirect(v, isNull) - if u != nil { - return u.UnmarshalJSON(item) - } - if ut != nil { - if item[0] != '"' { - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - val := "number" - switch item[0] { - case 'n': - val = "null" - case 't', 'f': - val = "bool" - } - d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) - return nil - } - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - return ut.UnmarshalText(s) - } - - v = pv - - switch c := item[0]; c { - case 'n': // null - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "null" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - v.Set(reflect.Zero(v.Type())) - // otherwise, ignore null for primitives/string - } - case 't', 'f': // true, false - value := item[0] == 't' - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "true" && string(item) != "false" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - default: - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - case reflect.Bool: - v.SetBool(value) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(value)) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - case '"': // string - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - switch v.Kind() { - default: - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Slice: - if v.Type().Elem().Kind() != reflect.Uint8 { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - b, err := base58.Decode(string(s)) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b) - case reflect.String: - v.SetString(string(s)) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(string(s))) - } else { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - default: // number - if c != '-' && (c < '0' || c > '9') { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - s := string(item) - switch v.Kind() { - default: - if v.Kind() == reflect.String && v.Type() == numberType { - v.SetString(s) - if !isValidNumber(s) { - return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) - } - break - } - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Interface: - n, err := d.convertNumber(s) - if err != nil { - d.saveError(err) - break - } - if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.Set(reflect.ValueOf(n)) - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetInt(n) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetUint(n) - - case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(s, v.Type().Bits()) - if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetFloat(n) - } - } - return nil -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() (val interface{}) { - switch d.opcode { - default: - panic(phasePanicMsg) - case scanBeginArray: - val = d.arrayInterface() - d.scanNext() - case scanBeginObject: - val = d.objectInterface() - d.scanNext() - case scanBeginLiteral: - val = d.literalInterface() - } - return -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []interface{} { - var v = make([]interface{}, 0) - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - v = append(v, d.valueInterface()) - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() map[string]interface{} { - m := make(map[string]interface{}) - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read string key. - start := d.readIndex() - d.scanWhile(scanContinue) - item := d.data[start:d.readIndex()] - key, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - // Read value. - m[key] = d.valueInterface() - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return m -} - -// literalInterface consumes and returns a literal from d.data[d.off-1:] and -// it reads the following byte ahead. The first byte of the literal has been -// read already (that's how the caller knows it's a literal). -func (d *decodeState) literalInterface() interface{} { - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.scanWhile(scanContinue) - - item := d.data[start:d.readIndex()] - - switch c := item[0]; c { - case 'n': // null - return nil - - case 't', 'f': // true, false - return c == 't' - - case '"': // string - s, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - return s - - default: // number - if c != '-' && (c < '0' || c > '9') { - panic(phasePanicMsg) - } - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - } - return n - } -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - var r rune - for _, c := range s[2:6] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { - s, ok = unquoteBytes(s) - t = string(s) - return -} - -func unquoteBytes(s []byte) (t []byte, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8.RuneSelf { - r++ - continue - } - rr, size := utf8.DecodeRune(s[r:]) - if rr == utf8.RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} diff --git a/types/jsonrpc/encoding/json/decode_test.go b/types/jsonrpc/encoding/json/decode_test.go deleted file mode 100644 index 1fb8c03eb..000000000 --- a/types/jsonrpc/encoding/json/decode_test.go +++ /dev/null @@ -1,2271 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( - "bytes" - "encoding" - "errors" - "fmt" - "image" - "math" - "math/big" - "net" - "reflect" - "strconv" - "strings" - "testing" - "time" -) - -type T struct { - X string - Y int - Z int `json:"-"` -} - -type U struct { - Alphabet string `json:"alpha"` -} - -type V struct { - F1 interface{} - F2 int32 - F3 Number - F4 *VOuter -} - -type VOuter struct { - V V -} - -type W struct { - S SS -} - -type SS string - -func (*SS) UnmarshalJSON(data []byte) error { - return &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS(""))} -} - -// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and -// without UseNumber -var ifaceNumAsFloat64 = map[string]interface{}{ - "k1": float64(1), - "k2": "s", - "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)}, - "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, -} - -var ifaceNumAsNumber = map[string]interface{}{ - "k1": Number("1"), - "k2": "s", - "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")}, - "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")}, -} - -type tx struct { - x int -} - -type u8 uint8 - -// A type that can unmarshal itself. - -type unmarshaler struct { - T bool -} - -func (u *unmarshaler) UnmarshalJSON(b []byte) error { - *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. - return nil -} - -type ustruct struct { - M unmarshaler -} - -type unmarshalerText struct { - A, B string -} - -// needed for re-marshaling tests -func (u unmarshalerText) MarshalText() ([]byte, error) { - return []byte(u.A + ":" + u.B), nil -} - -func (u *unmarshalerText) UnmarshalText(b []byte) error { - pos := bytes.IndexByte(b, ':') - if pos == -1 { - return errors.New("missing separator") - } - u.A, u.B = string(b[:pos]), string(b[pos+1:]) - return nil -} - -var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) - -type ustructText struct { - M unmarshalerText -} - -// u8marshal is an integer type that can marshal/unmarshal itself. -type u8marshal uint8 - -func (u8 u8marshal) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("u%d", u8)), nil -} - -var errMissingU8Prefix = errors.New("missing 'u' prefix") - -func (u8 *u8marshal) UnmarshalText(b []byte) error { - if !bytes.HasPrefix(b, []byte{'u'}) { - return errMissingU8Prefix - } - n, err := strconv.Atoi(string(b[1:])) - if err != nil { - return err - } - *u8 = u8marshal(n) - return nil -} - -var _ encoding.TextUnmarshaler = (*u8marshal)(nil) - -var ( - um0, um1 unmarshaler // target2 of unmarshaling - ump = &um1 - umtrue = unmarshaler{true} - umslice = []unmarshaler{{true}} - umslicep = new([]unmarshaler) - umstruct = ustruct{unmarshaler{true}} - - um0T, um1T unmarshalerText // target2 of unmarshaling - umpType = &um1T - umtrueXY = unmarshalerText{"x", "y"} - umsliceXY = []unmarshalerText{{"x", "y"}} - umslicepType = new([]unmarshalerText) - umstructType = new(ustructText) - umstructXY = ustructText{unmarshalerText{"x", "y"}} - - ummapType = map[unmarshalerText]bool{} - ummapXY = map[unmarshalerText]bool{{"x", "y"}: true} -) - -// Test data structures for anonymous fields. - -type Point struct { - Z int -} - -type Top struct { - Level0 int - Embed0 - *Embed0a - *Embed0b `json:"e,omitempty"` // treated as named - Embed0c `json:"-"` // ignored - Loop - Embed0p // has Point with X, Y, used - Embed0q // has Point with Z, used - embed // contains exported field -} - -type Embed0 struct { - Level1a int // overridden by Embed0a's Level1a with json tag - Level1b int // used because Embed0a's Level1b is renamed - Level1c int // used because Embed0a's Level1c is ignored - Level1d int // annihilated by Embed0a's Level1d - Level1e int `json:"x"` // annihilated by Embed0a.Level1e -} - -type Embed0a struct { - Level1a int `json:"Level1a,omitempty"` - Level1b int `json:"LEVEL1B,omitempty"` - Level1c int `json:"-"` - Level1d int // annihilated by Embed0's Level1d - Level1f int `json:"x"` // annihilated by Embed0's Level1e -} - -type Embed0b Embed0 - -type Embed0c Embed0 - -type Embed0p struct { - image.Point -} - -type Embed0q struct { - Point -} - -type embed struct { - Q int -} - -type Loop struct { - Loop1 int `json:",omitempty"` - Loop2 int `json:",omitempty"` - *Loop -} - -// From reflect test: -// The X in S6 and S7 annihilate, but they also block the X in S8.S9. -type S5 struct { - S6 - S7 - S8 -} - -type S6 struct { - X int -} - -type S7 S6 - -type S8 struct { - S9 -} - -type S9 struct { - X int - Y int -} - -// From reflect test: -// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. -type S10 struct { - S11 - S12 - S13 -} - -type S11 struct { - S6 -} - -type S12 struct { - S6 -} - -type S13 struct { - S8 -} - -type Ambig struct { - // Given "hello", the first match should win. - First int `json:"HELLO"` - Second int `json:"Hello"` -} - -type XYZ struct { - X interface{} - Y interface{} - Z interface{} -} - -func sliceAddr(x []int) *[]int { return &x } -func mapAddr(x map[string]int) *map[string]int { return &x } - -type byteWithMarshalJSON byte - -func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil -} - -func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalJSON(i) - return nil -} - -type byteWithPtrMarshalJSON byte - -func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return byteWithMarshalJSON(*b).MarshalJSON() -} - -func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type byteWithMarshalText byte - -func (b byteWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil -} - -func (b *byteWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalText(i) - return nil -} - -type byteWithPtrMarshalText byte - -func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { - return byteWithMarshalText(*b).MarshalText() -} - -func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*byteWithMarshalText)(b).UnmarshalText(data) -} - -type intWithMarshalJSON int - -func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil -} - -func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalJSON(i) - return nil -} - -type intWithPtrMarshalJSON int - -func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return intWithMarshalJSON(*b).MarshalJSON() -} - -func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*intWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type intWithMarshalText int - -func (b intWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil -} - -func (b *intWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalText(i) - return nil -} - -type intWithPtrMarshalText int - -func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { - return intWithMarshalText(*b).MarshalText() -} - -func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*intWithMarshalText)(b).UnmarshalText(data) -} - -type mapStringToStringData struct { - Data map[string]string `json:"data"` -} - -type unmarshalTest struct { - in string - ptr interface{} - out interface{} - err error - useNumber bool - golden bool - disallowUnknownFields bool -} - -type B struct { - B bool `json:",string"` -} - -var unmarshalTests = []unmarshalTest{ - // basic types - {in: `true`, ptr: new(bool), out: true}, - {in: `1`, ptr: new(int), out: 1}, - {in: `1.2`, ptr: new(float64), out: 1.2}, - {in: `-5`, ptr: new(int16), out: int16(-5)}, - {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, - {in: `2`, ptr: new(Number), out: Number("2")}, - {in: `2`, ptr: new(interface{}), out: float64(2.0)}, - {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true}, - {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, - {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, - {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, - {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, - {in: "null", ptr: new(interface{}), out: nil}, - {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}}, - {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, - {in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(SS("")), 0, "W", "S"}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, - - // raw values with whitespace - {in: "\n true ", ptr: new(bool), out: true}, - {in: "\t 1 ", ptr: new(int), out: 1}, - {in: "\r 1.2 ", ptr: new(float64), out: 1.2}, - {in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, - {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, - - // Z has a "-" tag. - {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, - {in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, - - {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, - {in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - - // syntax errors - {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, - {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, - {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, - {in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}}, - - // raw value errors - {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}}, - {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}}, - {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}}, - {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, - - // array tests - {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, - {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, - {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, - {in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")}, - - // empty array to interface test - {in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, - {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, - {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, - {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, - - // composite tests - {in: allValueIndent, ptr: new(All), out: allValue}, - {in: allValueCompact, ptr: new(All), out: allValue}, - {in: allValueIndent, ptr: new(*All), out: &allValue}, - {in: allValueCompact, ptr: new(*All), out: &allValue}, - {in: pallValueIndent, ptr: new(All), out: pallValue}, - {in: pallValueCompact, ptr: new(All), out: pallValue}, - {in: pallValueIndent, ptr: new(*All), out: &pallValue}, - {in: pallValueCompact, ptr: new(*All), out: &pallValue}, - - // unmarshal interface test - {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called - {in: `{"T":false}`, ptr: &ump, out: &umtrue}, - {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, - {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, - {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct}, - - // UnmarshalText interface test - {in: `"x:y"`, ptr: &um0T, out: umtrueXY}, - {in: `"x:y"`, ptr: &umpType, out: &umtrueXY}, - {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY}, - {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, - {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, - - // integer-keyed map test - { - in: `{"-1":"a","0":"b","1":"c"}`, - ptr: new(map[int]string), - out: map[int]string{-1: "a", 0: "b", 1: "c"}, - }, - { - in: `{"0":"a","10":"c","9":"b"}`, - ptr: new(map[u8]string), - out: map[u8]string{0: "a", 9: "b", 10: "c"}, - }, - { - in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, - ptr: new(map[int64]string), - out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, - }, - { - in: `{"18446744073709551615":"max"}`, - ptr: new(map[uint64]string), - out: map[uint64]string{math.MaxUint64: "max"}, - }, - { - in: `{"0":false,"10":true}`, - ptr: new(map[uintptr]bool), - out: map[uintptr]bool{0: false, 10: true}, - }, - - // Check that MarshalText and UnmarshalText take precedence - // over default integer handling in map keys. - { - in: `{"u2":4}`, - ptr: new(map[u8marshal]int), - out: map[u8marshal]int{2: 4}, - }, - { - in: `{"2":4}`, - ptr: new(map[u8marshal]int), - err: errMissingU8Prefix, - }, - - // integer-keyed map errors - { - in: `{"abc":"abc"}`, - ptr: new(map[int]string), - err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2}, - }, - { - in: `{"256":"abc"}`, - ptr: new(map[uint8]string), - err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2}, - }, - { - in: `{"128":"abc"}`, - ptr: new(map[int8]string), - err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2}, - }, - { - in: `{"-1":"abc"}`, - ptr: new(map[uint8]string), - err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2}, - }, - - // Map keys can be encoding.TextUnmarshalers. - {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, - // If multiple values for the same key exists, only the most recent value is used. - {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, - - // Overwriting of data. - // This is different from package xml, but it's what we've always done. - // Now documented and tested. - {in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}}, - {in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, - - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - out: Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - }, - }, - { - in: `{"hello": 1}`, - ptr: new(Ambig), - out: Ambig{First: 1}, - }, - - { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - out: S5{S8: S8{S9: S9{Y: 2}}}, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - - // invalid UTF-8 is coerced to valid UTF-8. - { - in: "\"hello\xffworld\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - in: "\"hello\xc2\xc2world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\xc2\xffworld\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\\ud800world\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", - ptr: new(string), - out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", - }, - - // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: &map[time.Time]string{}, - out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, - }, - - // issue 8305 - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: &map[Point]string{}, - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1}, - }, - { - in: `{"asdf": "hello world"}`, - ptr: &map[unmarshaler]string{}, - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1}, - }, - - // related to issue 13783. - // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, - // similar to marshaling a slice of typed int. - // These tests check that, assuming the byte type also has valid decoding methods, - // either the old base64 string encoding or the new per-element encoding can be - // successfully unmarshaled. The custom unmarshalers were accessible in earlier - // versions of Go, even though the custom marshaler was not. - // - // TODO: fix to base58 - //{ - // in: `"AQID"`, - // ptr: new([]byteWithMarshalJSON), - // out: []byteWithMarshalJSON{1, 2, 3}, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]byteWithMarshalJSON), - // out: []byteWithMarshalJSON{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `"AQID"`, - // ptr: new([]byteWithMarshalText), - // out: []byteWithMarshalText{1, 2, 3}, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]byteWithMarshalText), - // out: []byteWithMarshalText{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `"AQID"`, - // ptr: new([]byteWithPtrMarshalJSON), - // out: []byteWithPtrMarshalJSON{1, 2, 3}, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]byteWithPtrMarshalJSON), - // out: []byteWithPtrMarshalJSON{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `"AQID"`, - // ptr: new([]byteWithPtrMarshalText), - // out: []byteWithPtrMarshalText{1, 2, 3}, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]byteWithPtrMarshalText), - // out: []byteWithPtrMarshalText{1, 2, 3}, - // golden: true, - //}, - // - // ints work with the marshaler but not the base64 []byte case - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]intWithMarshalJSON), - // out: []intWithMarshalJSON{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]intWithMarshalText), - // out: []intWithMarshalText{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]intWithPtrMarshalJSON), - // out: []intWithPtrMarshalJSON{1, 2, 3}, - // golden: true, - //}, - //{ - // in: `["Z01","Z02","Z03"]`, - // ptr: new([]intWithPtrMarshalText), - // out: []intWithPtrMarshalText{1, 2, 3}, - // golden: true, - //}, - - {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true}, - {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true}, - {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true}, - {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true}, - {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true}, - {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true}, - {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true}, - {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true}, - {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true}, - {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true}, - {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false}, - - { - in: `{"V": {"F2": "hello"}}`, - ptr: new(VOuter), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "F2", - Type: reflect.TypeOf(int32(0)), - Offset: 20, - }, - }, - { - in: `{"V": {"F4": {}, "F2": "hello"}}`, - ptr: new(VOuter), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "F2", - Type: reflect.TypeOf(int32(0)), - Offset: 30, - }, - }, - - // issue 15146. - // invalid inputs in wrongStringTests below. - {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true}, - {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true}, - {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)}, - {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)}, - {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, - {in: `{"B": "null"}`, ptr: new(B), out: B{false}}, - {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, - {in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)}, - - // additional tests for disallowUnknownFields - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18, - "extra": true - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12, - "extra": null - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - // issue 26444 - // UnmarshalTypeError without field & struct values - { - in: `{"data":{"test1": "bob", "test2": 123}}`, - ptr: new(mapStringToStringData), - err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, - }, - { - in: `{"data":{"test1": 123, "test2": "bob"}}`, - ptr: new(mapStringToStringData), - err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, - }, - - // trying to decode JSON arrays or objects via TextUnmarshaler - { - in: `[1, 2, 3]`, - ptr: new(MustNotUnmarshalText), - err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - }, - { - in: `{"foo": "bar"}`, - ptr: new(MustNotUnmarshalText), - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - }, -} - -func TestMarshal(t *testing.T) { - b, err := Marshal(allValue) - if err != nil { - t.Fatalf("Marshal allValue: %v", err) - } - if string(b) != allValueCompact { - t.Errorf("Marshal allValueCompact") - diff(t, b, []byte(allValueCompact)) - return - } - - b, err = Marshal(pallValue) - if err != nil { - t.Fatalf("Marshal pallValue: %v", err) - } - if string(b) != pallValueCompact { - t.Errorf("Marshal pallValueCompact") - diff(t, b, []byte(pallValueCompact)) - return - } -} - -var badUTF8 = []struct { - in, out string -}{ - {"hello\xffworld", `"hello\ufffdworld"`}, - {"", `""`}, - {"\xff", `"\ufffd"`}, - {"\xff\xff", `"\ufffd\ufffd"`}, - {"a\xffb", `"a\ufffdb"`}, - {"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`}, -} - -func TestMarshalBadUTF8(t *testing.T) { - for _, tt := range badUTF8 { - b, err := Marshal(tt.in) - if string(b) != tt.out || err != nil { - t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out) - } - } -} - -func TestMarshalNumberZeroVal(t *testing.T) { - var n Number - out, err := Marshal(n) - if err != nil { - t.Fatal(err) - } - outStr := string(out) - if outStr != "0" { - t.Fatalf("Invalid zero val for Number: %q", outStr) - } -} - -func TestMarshalEmbeds(t *testing.T) { - top := &Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - } - b, err := Marshal(top) - if err != nil { - t.Fatal(err) - } - want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}" - if string(b) != want { - t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want) - } -} - -func TestUnmarshal(t *testing.T) { - for i, tt := range unmarshalTests { - var scan scanner - in := []byte(tt.in) - if err := checkValid(in, &scan); err != nil { - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: checkValid: %#v", i, err) - continue - } - } - if tt.ptr == nil { - continue - } - - // v = new(right-type) - v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec := NewDecoder(bytes.NewReader(in)) - if tt.useNumber { - dec.UseNumber() - } - if tt.disallowUnknownFields { - dec.DisallowUnknownFields() - } - if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: %v, want %v", i, err, tt.err) - continue - } else if err != nil { - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) - data, _ := Marshal(v.Elem().Interface()) - println(string(data)) - data, _ = Marshal(tt.out) - println(string(data)) - continue - } - - // Check round trip also decodes correctly. - if tt.err == nil { - enc, err := Marshal(v.Interface()) - if err != nil { - t.Errorf("#%d: error re-marshaling: %v", i, err) - continue - } - if tt.golden && !bytes.Equal(enc, in) { - t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) - } - vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec = NewDecoder(bytes.NewReader(enc)) - if tt.useNumber { - dec.UseNumber() - } - if err := dec.Decode(vv.Interface()); err != nil { - t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) - t.Errorf(" In: %q", strings.Map(noSpace, string(in))) - t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) - continue - } - } - } -} - -func TestUnmarshalMarshal(t *testing.T) { - initBig() - var v interface{} - if err := Unmarshal(jsonBig, &v); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - b, err := Marshal(v) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if !bytes.Equal(jsonBig, b) { - t.Errorf("Marshal jsonBig") - diff(t, b, jsonBig) - return - } -} - -var numberTests = []struct { - in string - i int64 - intErr string - f float64 - floatErr string -}{ - {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, - {in: "-12", i: -12, f: -12.0}, - {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, -} - -// Independent of Decode, basic coverage of the accessors in Number -func TestNumberAccessors(t *testing.T) { - for _, tt := range numberTests { - n := Number(tt.in) - if s := n.String(); s != tt.in { - t.Errorf("Number(%q).String() is %q", tt.in, s) - } - if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { - t.Errorf("Number(%q).Int64() is %d", tt.in, i) - } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { - t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err) - } - if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { - t.Errorf("Number(%q).Float64() is %g", tt.in, f) - } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { - t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err) - } - } -} - -func TestLargeByteSlice(t *testing.T) { - s0 := make([]byte, 2000) - for i := range s0 { - s0[i] = byte(i) - } - b, err := Marshal(s0) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - var s1 []byte - if err := Unmarshal(b, &s1); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !bytes.Equal(s0, s1) { - t.Errorf("Marshal large byte slice") - diff(t, s0, s1) - } -} - -type Xint struct { - X int -} - -func TestUnmarshalInterface(t *testing.T) { - var xint Xint - var i interface{} = &xint - if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("Did not write to xint") - } -} - -func TestUnmarshalPtrPtr(t *testing.T) { - var xint Xint - pxint := &xint - if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("Did not write to xint") - } -} - -func TestEscape(t *testing.T) { - const input = `"foobar"` + " [\u2028 \u2029]" - const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"` - b, err := Marshal(input) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if s := string(b); s != expected { - t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected) - } -} - -// WrongString is a struct that's misusing the ,string modifier. -type WrongString struct { - Message string `json:"result,string"` -} - -type wrongStringTest struct { - in, err string -} - -var wrongStringTests = []wrongStringTest{ - {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, - {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, - {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, - {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, -} - -// If people misuse the ,string modifier, the error message should be -// helpful, telling the user that they're doing it wrong. -func TestErrorMessageFromMisusedString(t *testing.T) { - for n, tt := range wrongStringTests { - r := strings.NewReader(tt.in) - var s WrongString - err := NewDecoder(r).Decode(&s) - got := fmt.Sprintf("%v", err) - if got != tt.err { - t.Errorf("%d. got err = %q, want %q", n, got, tt.err) - } - } -} - -func noSpace(c rune) rune { - if isSpace(byte(c)) { //only used for ascii - return -1 - } - return c -} - -type All struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Uintptr uintptr - Float32 float32 - Float64 float64 - - Foo string `json:"bar"` - Foo2 string `json:"bar2,dummyopt"` - - IntStr int64 `json:",string"` - UintptrStr uintptr `json:",string"` - - PBool *bool - PInt *int - PInt8 *int8 - PInt16 *int16 - PInt32 *int32 - PInt64 *int64 - PUint *uint - PUint8 *uint8 - PUint16 *uint16 - PUint32 *uint32 - PUint64 *uint64 - PUintptr *uintptr - PFloat32 *float32 - PFloat64 *float64 - - String string - PString *string - - Map map[string]Small - MapP map[string]*Small - PMap *map[string]Small - PMapP *map[string]*Small - - EmptyMap map[string]Small - NilMap map[string]Small - - Slice []Small - SliceP []*Small - PSlice *[]Small - PSliceP *[]*Small - - EmptySlice []Small - NilSlice []Small - - StringSlice []string - ByteSlice []byte - - Small Small - PSmall *Small - PPSmall **Small - - Interface interface{} - PInterface *interface{} - - unexported int -} - -type Small struct { - Tag string -} - -var allValue = All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Uintptr: 12, - Float32: 14.1, - Float64: 15.1, - Foo: "foo", - Foo2: "foo2", - IntStr: 42, - UintptrStr: 44, - String: "16", - Map: map[string]Small{ - "17": {Tag: "tag17"}, - "18": {Tag: "tag18"}, - }, - MapP: map[string]*Small{ - "19": {Tag: "tag19"}, - "20": nil, - }, - EmptyMap: map[string]Small{}, - Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, - SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, - EmptySlice: []Small{}, - StringSlice: []string{"str24", "str25", "str26"}, - ByteSlice: []byte{27, 28, 29}, - Small: Small{Tag: "tag30"}, - PSmall: &Small{Tag: "tag31"}, - Interface: 5.2, -} - -var pallValue = All{ - PBool: &allValue.Bool, - PInt: &allValue.Int, - PInt8: &allValue.Int8, - PInt16: &allValue.Int16, - PInt32: &allValue.Int32, - PInt64: &allValue.Int64, - PUint: &allValue.Uint, - PUint8: &allValue.Uint8, - PUint16: &allValue.Uint16, - PUint32: &allValue.Uint32, - PUint64: &allValue.Uint64, - PUintptr: &allValue.Uintptr, - PFloat32: &allValue.Float32, - PFloat64: &allValue.Float64, - PString: &allValue.String, - PMap: &allValue.Map, - PMapP: &allValue.MapP, - PSlice: &allValue.Slice, - PSliceP: &allValue.SliceP, - PPSmall: &allValue.PSmall, - PInterface: &allValue.Interface, -} - -var allValueIndent = `{ - "Bool": true, - "Int": 2, - "Int8": 3, - "Int16": 4, - "Int32": 5, - "Int64": 6, - "Uint": 7, - "Uint8": 8, - "Uint16": 9, - "Uint32": 10, - "Uint64": 11, - "Uintptr": 12, - "Float32": 14.1, - "Float64": 15.1, - "bar": "foo", - "bar2": "foo2", - "IntStr": "42", - "UintptrStr": "44", - "PBool": null, - "PInt": null, - "PInt8": null, - "PInt16": null, - "PInt32": null, - "PInt64": null, - "PUint": null, - "PUint8": null, - "PUint16": null, - "PUint32": null, - "PUint64": null, - "PUintptr": null, - "PFloat32": null, - "PFloat64": null, - "String": "16", - "PString": null, - "Map": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "MapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "PMap": null, - "PMapP": null, - "EmptyMap": {}, - "NilMap": null, - "Slice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "SliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "PSlice": null, - "PSliceP": null, - "EmptySlice": [], - "NilSlice": null, - "StringSlice": [ - "str24", - "str25", - "str26" - ], - "ByteSlice": "A79E", - "Small": { - "Tag": "tag30" - }, - "PSmall": { - "Tag": "tag31" - }, - "PPSmall": null, - "Interface": 5.2, - "PInterface": null -}` - -var allValueCompact = strings.Map(noSpace, allValueIndent) - -var pallValueIndent = `{ - "Bool": false, - "Int": 0, - "Int8": 0, - "Int16": 0, - "Int32": 0, - "Int64": 0, - "Uint": 0, - "Uint8": 0, - "Uint16": 0, - "Uint32": 0, - "Uint64": 0, - "Uintptr": 0, - "Float32": 0, - "Float64": 0, - "bar": "", - "bar2": "", - "IntStr": "0", - "UintptrStr": "0", - "PBool": true, - "PInt": 2, - "PInt8": 3, - "PInt16": 4, - "PInt32": 5, - "PInt64": 6, - "PUint": 7, - "PUint8": 8, - "PUint16": 9, - "PUint32": 10, - "PUint64": 11, - "PUintptr": 12, - "PFloat32": 14.1, - "PFloat64": 15.1, - "String": "", - "PString": "16", - "Map": null, - "MapP": null, - "PMap": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "PMapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "EmptyMap": null, - "NilMap": null, - "Slice": null, - "SliceP": null, - "PSlice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "PSliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "EmptySlice": null, - "NilSlice": null, - "StringSlice": null, - "ByteSlice": null, - "Small": { - "Tag": "" - }, - "PSmall": null, - "PPSmall": { - "Tag": "tag31" - }, - "Interface": null, - "PInterface": 5.2 -}` - -var pallValueCompact = strings.Map(noSpace, pallValueIndent) - -func TestRefUnmarshal(t *testing.T) { - type S struct { - // Ref is defined in encode_test.go. - R0 Ref - R1 *Ref - R2 RefText - R3 *RefText - } - want := S{ - R0: 12, - R1: new(Ref), - R2: 13, - R3: new(RefText), - } - *want.R1 = 12 - *want.R3 = 13 - - var got S - if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(got, want) { - t.Errorf("got %+v, want %+v", got, want) - } -} - -// Test that the empty string doesn't panic decoding when ,string is specified -// Issue 3450 -func TestEmptyString(t *testing.T) { - type T2 struct { - Number1 int `json:",string"` - Number2 int `json:",string"` - } - data := `{"Number1":"1", "Number2":""}` - dec := NewDecoder(strings.NewReader(data)) - var t2 T2 - err := dec.Decode(&t2) - if err == nil { - t.Fatal("Decode: did not return error") - } - if t2.Number1 != 1 { - t.Fatal("Decode: did not set Number1") - } -} - -// Test that a null for ,string is not replaced with the previous quoted string (issue 7046). -// It should also not be an error (issue 2540, issue 8587). -func TestNullString(t *testing.T) { - type T struct { - A int `json:",string"` - B int `json:",string"` - C *int `json:",string"` - } - data := []byte(`{"A": "1", "B": null, "C": null}`) - var s T - s.B = 1 - s.C = new(int) - *s.C = 2 - err := Unmarshal(data, &s) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if s.B != 1 || s.C != nil { - t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) - } -} - -func intp(x int) *int { - p := new(int) - *p = x - return p -} - -func intpp(x *int) **int { - pp := new(*int) - *pp = x - return pp -} - -var interfaceSetTests = []struct { - pre interface{} - json string - post interface{} -}{ - {"foo", `"bar"`, "bar"}, - {"foo", `2`, 2.0}, - {"foo", `true`, true}, - {"foo", `null`, nil}, - - {nil, `null`, nil}, - {new(int), `null`, nil}, - {(*int)(nil), `null`, nil}, - {new(*int), `null`, new(*int)}, - {(**int)(nil), `null`, nil}, - {intp(1), `null`, nil}, - {intpp(nil), `null`, intpp(nil)}, - {intpp(intp(1)), `null`, intpp(nil)}, -} - -func TestInterfaceSet(t *testing.T) { - for _, tt := range interfaceSetTests { - b := struct{ X interface{} }{tt.pre} - blob := `{"X":` + tt.json + `}` - if err := Unmarshal([]byte(blob), &b); err != nil { - t.Errorf("Unmarshal %#q: %v", blob, err) - continue - } - if !reflect.DeepEqual(b.X, tt.post) { - t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post) - } - } -} - -type NullTest struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Float32 float32 - Float64 float64 - String string - PBool *bool - Map map[string]string - Slice []string - Interface interface{} - - PRaw *RawMessage - PTime *time.Time - PBigInt *big.Int - PText *MustNotUnmarshalText - PBuffer *bytes.Buffer // has methods, just not relevant ones - PStruct *struct{} - - Raw RawMessage - Time time.Time - BigInt big.Int - Text MustNotUnmarshalText - Buffer bytes.Buffer - Struct struct{} -} - -type NullTestStrings struct { - Bool bool `json:",string"` - Int int `json:",string"` - Int8 int8 `json:",string"` - Int16 int16 `json:",string"` - Int32 int32 `json:",string"` - Int64 int64 `json:",string"` - Uint uint `json:",string"` - Uint8 uint8 `json:",string"` - Uint16 uint16 `json:",string"` - Uint32 uint32 `json:",string"` - Uint64 uint64 `json:",string"` - Float32 float32 `json:",string"` - Float64 float64 `json:",string"` - String string `json:",string"` - PBool *bool `json:",string"` - Map map[string]string `json:",string"` - Slice []string `json:",string"` - Interface interface{} `json:",string"` - - PRaw *RawMessage `json:",string"` - PTime *time.Time `json:",string"` - PBigInt *big.Int `json:",string"` - PText *MustNotUnmarshalText `json:",string"` - PBuffer *bytes.Buffer `json:",string"` - PStruct *struct{} `json:",string"` - - Raw RawMessage `json:",string"` - Time time.Time `json:",string"` - BigInt big.Int `json:",string"` - Text MustNotUnmarshalText `json:",string"` - Buffer bytes.Buffer `json:",string"` - Struct struct{} `json:",string"` -} - -// JSON null values should be ignored for primitives and string values instead of resulting in an error. -// Issue 2540 -func TestUnmarshalNulls(t *testing.T) { - // Unmarshal docs: - // The JSON null value unmarshals into an interface, map, pointer, or slice - // by setting that Go value to nil. Because null is often used in JSON to mean - // ``not present,'' unmarshaling a JSON null into any other Go type has no effect - // on the value and produces no error. - - jsonData := []byte(`{ - "Bool" : null, - "Int" : null, - "Int8" : null, - "Int16" : null, - "Int32" : null, - "Int64" : null, - "Uint" : null, - "Uint8" : null, - "Uint16" : null, - "Uint32" : null, - "Uint64" : null, - "Float32" : null, - "Float64" : null, - "String" : null, - "PBool": null, - "Map": null, - "Slice": null, - "Interface": null, - "PRaw": null, - "PTime": null, - "PBigInt": null, - "PText": null, - "PBuffer": null, - "PStruct": null, - "Raw": null, - "Time": null, - "BigInt": null, - "Text": null, - "Buffer": null, - "Struct": null - }`) - nulls := NullTest{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Float32: 12.1, - Float64: 13.1, - String: "14", - PBool: new(bool), - Map: map[string]string{}, - Slice: []string{}, - Interface: new(MustNotUnmarshalJSON), - PRaw: new(RawMessage), - PTime: new(time.Time), - PBigInt: new(big.Int), - PText: new(MustNotUnmarshalText), - PStruct: new(struct{}), - PBuffer: new(bytes.Buffer), - Raw: RawMessage("123"), - Time: time.Unix(123456789, 0), - BigInt: *big.NewInt(123), - } - - before := nulls.Time.String() - - err := Unmarshal(jsonData, &nulls) - if err != nil { - t.Errorf("Unmarshal of null values failed: %v", err) - } - if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || - nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || - nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { - t.Errorf("Unmarshal of null values affected primitives") - } - - if nulls.PBool != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBool") - } - if nulls.Map != nil { - t.Errorf("Unmarshal of null did not clear nulls.Map") - } - if nulls.Slice != nil { - t.Errorf("Unmarshal of null did not clear nulls.Slice") - } - if nulls.Interface != nil { - t.Errorf("Unmarshal of null did not clear nulls.Interface") - } - if nulls.PRaw != nil { - t.Errorf("Unmarshal of null did not clear nulls.PRaw") - } - if nulls.PTime != nil { - t.Errorf("Unmarshal of null did not clear nulls.PTime") - } - if nulls.PBigInt != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBigInt") - } - if nulls.PText != nil { - t.Errorf("Unmarshal of null did not clear nulls.PText") - } - if nulls.PBuffer != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBuffer") - } - if nulls.PStruct != nil { - t.Errorf("Unmarshal of null did not clear nulls.PStruct") - } - - if string(nulls.Raw) != "null" { - t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw)) - } - if nulls.Time.String() != before { - t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String()) - } - if nulls.BigInt.String() != "123" { - t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String()) - } -} - -type MustNotUnmarshalJSON struct{} - -func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error { - return errors.New("MustNotUnmarshalJSON was used") -} - -type MustNotUnmarshalText struct{} - -func (x MustNotUnmarshalText) UnmarshalText(text []byte) error { - return errors.New("MustNotUnmarshalText was used") -} - -func TestStringKind(t *testing.T) { - type stringKind string - - var m1, m2 map[stringKind]int - m1 = map[stringKind]int{ - "foo": 42, - } - - data, err := Marshal(m1) - if err != nil { - t.Errorf("Unexpected error marshaling: %v", err) - } - - err = Unmarshal(data, &m2) - if err != nil { - t.Errorf("Unexpected error unmarshaling: %v", err) - } - - if !reflect.DeepEqual(m1, m2) { - t.Error("Items should be equal after encoding and then decoding") - } -} - -// Custom types with []byte as underlying type could not be marshaled -// and then unmarshaled. -// Issue 8962. -func TestByteKind(t *testing.T) { - type byteKind []byte - - a := byteKind("hello") - - data, err := Marshal(a) - if err != nil { - t.Error(err) - } - var b byteKind - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Errorf("expected %v == %v", a, b) - } -} - -// The fix for issue 8962 introduced a regression. -// Issue 12921. -func TestSliceOfCustomByte(t *testing.T) { - type Uint8 uint8 - - a := []Uint8("hello") - - data, err := Marshal(a) - if err != nil { - t.Fatal(err) - } - var b []Uint8 - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Fatalf("expected %v == %v", a, b) - } -} - -var decodeTypeErrorTests = []struct { - dest interface{} - src string -}{ - {new(string), `{"user": "name"}`}, // issue 4628. - {new(error), `{}`}, // issue 4222 - {new(error), `[]`}, - {new(error), `""`}, - {new(error), `123`}, - {new(error), `true`}, -} - -func TestUnmarshalTypeError(t *testing.T) { - for _, item := range decodeTypeErrorTests { - err := Unmarshal([]byte(item.src), item.dest) - if _, ok := err.(*UnmarshalTypeError); !ok { - t.Errorf("expected type error for Unmarshal(%q, type %T): got %T", - item.src, item.dest, err) - } - } -} - -var unmarshalSyntaxTests = []string{ - "tru", - "fals", - "nul", - "123e", - `"hello`, - `[1,2,3`, - `{"key":1`, - `{"key":1,`, -} - -func TestUnmarshalSyntax(t *testing.T) { - var x interface{} - for _, src := range unmarshalSyntaxTests { - err := Unmarshal([]byte(src), &x) - if _, ok := err.(*SyntaxError); !ok { - t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err) - } - } -} - -// Test handling of unexported fields that should be ignored. -// Issue 4660 -type unexportedFields struct { - Name string - m map[string]interface{} `json:"-"` - m2 map[string]interface{} `json:"abcd"` - - s []int `json:"-"` -} - -func TestUnmarshalUnexported(t *testing.T) { - input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}` - want := &unexportedFields{Name: "Bob"} - - out := &unexportedFields{} - err := Unmarshal([]byte(input), out) - if err != nil { - t.Errorf("got error %v, expected nil", err) - } - if !reflect.DeepEqual(out, want) { - t.Errorf("got %q, want %q", out, want) - } -} - -// Time3339 is a time.Time which encodes to and from JSON -// as an RFC 3339 time in UTC. -type Time3339 time.Time - -func (t *Time3339) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) - } - tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) - if err != nil { - return err - } - *t = Time3339(tm) - return nil -} - -func TestUnmarshalJSONLiteralError(t *testing.T) { - var t3 Time3339 - err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3) - if err == nil { - t.Fatalf("expected error; got time %v", time.Time(t3)) - } - if !strings.Contains(err.Error(), "range") { - t.Errorf("got err = %v; want out of range error", err) - } -} - -// Test that extra object elements in an array do not result in a -// "data changing underfoot" error. -// Issue 3717 -func TestSkipArrayObjects(t *testing.T) { - json := `[{}]` - var dest [0]interface{} - - err := Unmarshal([]byte(json), &dest) - if err != nil { - t.Errorf("got error %q, want nil", err) - } -} - -// Test semantics of pre-filled struct fields and pre-filled map fields. -// Issue 4900. -func TestPrefilled(t *testing.T) { - ptrToMap := func(m map[string]interface{}) *map[string]interface{} { return &m } - - // Values here change, cannot reuse table across runs. - var prefillTests = []struct { - in string - ptr interface{} - out interface{} - }{ - { - in: `{"X": 1, "Y": 2}`, - ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, - out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, - }, - { - in: `{"X": 1, "Y": 2}`, - ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}), - out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}), - }, - } - - for _, tt := range prefillTests { - ptrstr := fmt.Sprintf("%v", tt.ptr) - err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here - if err != nil { - t.Errorf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out) - } - } -} - -var invalidUnmarshalTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, -} - -func TestInvalidUnmarshal(t *testing.T) { - buf := []byte(`{"a":"1"}`) - for _, tt := range invalidUnmarshalTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - if got := err.Error(); got != tt.want { - t.Errorf("Unmarshal = %q; want %q", got, tt.want) - } - } -} - -var invalidUnmarshalTextTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, - {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"}, -} - -func TestInvalidUnmarshalText(t *testing.T) { - buf := []byte(`123`) - for _, tt := range invalidUnmarshalTextTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - if got := err.Error(); got != tt.want { - t.Errorf("Unmarshal = %q; want %q", got, tt.want) - } - } -} - -// Test that string option is ignored for invalid types. -// Issue 9812. -func TestInvalidStringOption(t *testing.T) { - num := 0 - item := struct { - T time.Time `json:",string"` - M map[string]string `json:",string"` - S []string `json:",string"` - A [1]string `json:",string"` - I interface{} `json:",string"` - P *int `json:",string"` - }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} - - data, err := Marshal(item) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - - err = Unmarshal(data, &item) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } -} - -// Test unmarshal behavior with regards to embedded unexported structs. -// -// (Issue 21357) If the embedded struct is a pointer and is unallocated, -// this returns an error because unmarshal cannot set the field. -// -// (Issue 24152) If the embedded struct is given an explicit name, -// ensure that the normal unmarshal logic does not panic in reflect. -func TestUnmarshalEmbeddedUnexported(t *testing.T) { - type ( - embed1 struct{ Q int } - embed2 struct{ Q int } - embed3 struct { - Q int64 `json:",string"` - } - S1 struct { - *embed1 - R int - } - S2 struct { - *embed1 - Q int - } - S3 struct { - embed1 - R int - } - S4 struct { - *embed1 - embed2 - } - S5 struct { - *embed3 - R int - } - S6 struct { - embed1 `json:"embed1"` - } - S7 struct { - embed1 `json:"embed1"` - embed2 - } - S8 struct { - embed1 `json:"embed1"` - embed2 `json:"embed2"` - Q int - } - ) - - tests := []struct { - in string - ptr interface{} - out interface{} - err error - }{{ - // Error since we cannot set S1.embed1, but still able to set S1.R. - in: `{"R":2,"Q":1}`, - ptr: new(S1), - out: &S1{R: 2}, - err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"), - }, { - // The top level Q field takes precedence. - in: `{"Q":1}`, - ptr: new(S2), - out: &S2{Q: 1}, - }, { - // No issue with non-pointer variant. - in: `{"R":2,"Q":1}`, - ptr: new(S3), - out: &S3{embed1: embed1{Q: 1}, R: 2}, - }, { - // No error since both embedded structs have field R, which annihilate each other. - // Thus, no attempt is made at setting S4.embed1. - in: `{"R":2}`, - ptr: new(S4), - out: new(S4), - }, { - // Error since we cannot set S5.embed1, but still able to set S5.R. - in: `{"R":2,"Q":1}`, - ptr: new(S5), - out: &S5{R: 2}, - err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"), - }, { - // Issue 24152, ensure decodeState.indirect does not panic. - in: `{"embed1": {"Q": 1}}`, - ptr: new(S6), - out: &S6{embed1{1}}, - }, { - // Issue 24153, check that we can still set forwarded fields even in - // the presence of a name conflict. - // - // This relies on obscure behavior of reflect where it is possible - // to set a forwarded exported field on an unexported embedded struct - // even though there is a name conflict, even when it would have been - // impossible to do so according to Go visibility rules. - // Go forbids this because it is ambiguous whether S7.Q refers to - // S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported, - // it should be impossible for an external package to set either Q. - // - // It is probably okay for a future reflect change to break this. - in: `{"embed1": {"Q": 1}, "Q": 2}`, - ptr: new(S7), - out: &S7{embed1{1}, embed2{2}}, - }, { - // Issue 24153, similar to the S7 case. - in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`, - ptr: new(S8), - out: &S8{embed1{1}, embed2{2}, 3}, - }} - - for i, tt := range tests { - err := Unmarshal([]byte(tt.in), tt.ptr) - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: %v, want %v", i, err, tt.err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("#%d: mismatch\ngot: %#+v\nwant: %#+v", i, tt.ptr, tt.out) - } - } -} - -type unmarshalPanic struct{} - -func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) } - -func TestUnmarshalPanic(t *testing.T) { - defer func() { - if got := recover(); !reflect.DeepEqual(got, 0xdead) { - t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) - } - }() - Unmarshal([]byte("{}"), &unmarshalPanic{}) - t.Fatalf("Unmarshal should have panicked") -} diff --git a/types/jsonrpc/encoding/json/encode.go b/types/jsonrpc/encoding/json/encode.go deleted file mode 100644 index 26b0c472a..000000000 --- a/types/jsonrpc/encoding/json/encode.go +++ /dev/null @@ -1,1253 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 7159. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package json - -import ( - "bytes" - "encoding" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" - - "github.com/aergoio/aergo/v2/internal/enc/base58" -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements the Marshaler interface -// and is not a nil pointer, Marshal calls its MarshalJSON method -// to produce JSON. If no MarshalJSON method is present but the -// value implements encoding.TextMarshaler instead, Marshal calls -// its MarshalText method and encodes the result as a JSON string. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// UnmarshalJSON. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and Number values encode as JSON numbers. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" -// to keep some browsers from misinterpreting JSON output as HTML. -// Ampersand "&" is also escaped to "\u0026" for the same reason. -// This escaping can be disabled using an Encoder that had SetEscapeHTML(false) -// called on it. -// -// Array and slice values encode as JSON arrays, except that -// []byte encodes as a base64-encoded string, and a nil slice -// encodes as the null JSON value. -// -// Struct values encode as JSON objects. -// Each exported struct field becomes a member of the object, using the -// field name as the object key, unless the field is omitted for one of the -// reasons given below. -// -// The encoding of each struct field can be customized by the format string -// stored under the "json" key in the struct field's tag. -// The format string gives the name of the field, possibly followed by a -// comma-separated list of options. The name may be empty in order to -// specify options without overriding the default field name. -// -// The "omitempty" option specifies that the field should be omitted -// from the encoding if the field has an empty value, defined as -// false, 0, a nil pointer, a nil interface value, and any empty array, -// slice, map, or string. -// -// As a special case, if the field tag is "-", the field is always omitted. -// Note that a field with name "-" can still be generated using the tag "-,". -// -// Examples of struct field tags and their meanings: -// -// // Field appears in JSON as key "myName". -// Field int `json:"myName"` -// -// // Field appears in JSON as key "myName" and -// // the field is omitted from the object if its value is empty, -// // as defined above. -// Field int `json:"myName,omitempty"` -// -// // Field appears in JSON as key "Field" (the default), but -// // the field is skipped if empty. -// // Note the leading comma. -// Field int `json:",omitempty"` -// -// // Field is ignored by this package. -// Field int `json:"-"` -// -// // Field appears in JSON as key "-". -// Field int `json:"-,"` -// -// The "string" option signals that a field is stored as JSON inside a -// JSON-encoded string. It applies only to fields of string, floating point, -// integer, or boolean types. This extra level of encoding is sometimes used -// when communicating with JavaScript programs: -// -// Int64String int64 `json:",string"` -// -// The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, and ASCII punctuation except quotation -// marks, backslash, and comma. -// -// Anonymous struct fields are usually marshaled as if their inner exported fields -// were fields in the outer struct, subject to the usual Go visibility rules amended -// as described in the next paragraph. -// An anonymous struct field with a name given in its JSON tag is treated as -// having that name, rather than being anonymous. -// An anonymous struct field of interface type is treated the same as having -// that type as its name, rather than being anonymous. -// -// The Go visibility rules for struct fields are amended for JSON when -// deciding which field to marshal or unmarshal. If there are -// multiple fields at the same level, and that level is the least -// nested (and would therefore be the nesting level selected by the -// usual Go rules), the following extra rules apply: -// -// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, -// even if there are multiple untagged fields that would otherwise conflict. -// -// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. -// -// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. -// -// Handling of anonymous struct fields is new in Go 1.1. -// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of -// an anonymous struct field in both current and earlier versions, give the field -// a JSON tag of "-". -// -// Map values encode as JSON objects. The map's key type must either be a -// string, an integer type, or implement encoding.TextMarshaler. The map keys -// are sorted and used as JSON object keys by applying the following rules, -// subject to the UTF-8 coercion described for string values above: -// - string keys are used directly -// - encoding.TextMarshalers are marshaled -// - integer keys are converted to strings -// -// Pointer values encode as the value pointed to. -// A nil pointer encodes as the null JSON value. -// -// Interface values encode as the value contained in the interface. -// A nil interface value encodes as the null JSON value. -// -// Channel, complex, and function values cannot be encoded in JSON. -// Attempting to encode such a value causes Marshal to return -// an UnsupportedTypeError. -// -// JSON cannot represent cyclic data structures and Marshal does not -// handle them. Passing cyclic structures to Marshal will result in -// an infinite recursion. -func Marshal(v interface{}) ([]byte, error) { - e := newEncodeState() - - err := e.marshal(v, encOpts{escapeHTML: true}) - if err != nil { - return nil, err - } - buf := append([]byte(nil), e.Bytes()...) - - e.Reset() - encodeStatePool.Put(e) - - return buf, nil -} - -// MarshalIndent is like Marshal but applies Indent to format the output. -// Each JSON element in the output will begin on a new line beginning with prefix -// followed by one or more copies of indent according to the indentation nesting. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - b, err := Marshal(v) - if err != nil { - return nil, err - } - var buf bytes.Buffer - err = Indent(&buf, b, prefix, indent) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 -// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 -// so that the JSON will be safe to embed inside HTML