diff --git a/core/kernel.go b/core/kernel.go index f00cd7a9b17d0d03f690ddcd2c135a6c33b63795..e854d62be5f81975239d476ab646ab3420434f32 100644 --- a/core/kernel.go +++ b/core/kernel.go @@ -50,7 +50,7 @@ const ServerShutdownTimeoutMilliseconds = 1000 type Kernel struct { // Expose these public-facing interfaces to allow programmatic extension of the Kernel by other projects Emitter event.Emitter - Service rpc.Service + Service *rpc.Service Launchers []process.Launcher Logger logging_types.InfoTraceLogger processes map[string]process.Process diff --git a/execution/evm/vm.go b/execution/evm/vm.go index 98fd2943281ce862ed1bdcda0e7fc60eb811dd19..ed760c175ea2567e33c05a1c171e0d50a0380fb1 100644 --- a/execution/evm/vm.go +++ b/execution/evm/vm.go @@ -19,6 +19,9 @@ import ( "errors" "fmt" + "io/ioutil" + "strings" + acm "github.com/hyperledger/burrow/account" . "github.com/hyperledger/burrow/binary" "github.com/hyperledger/burrow/event" @@ -201,6 +204,16 @@ func (vm *VM) call(caller, callee acm.MutableAccount, code, input []byte, value vm.Debugf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address().Bytes()[:4], callee.Address(), len(callee.Code()), *gas, input) + tokens, err := acm.Bytecode(code).Tokens() + if err != nil { + return nil, err + } + tokens = append(tokens, "") + err = ioutil.WriteFile(fmt.Sprintf("tokens-%x.txt", vm.txHash[:4]), []byte(strings.Join(tokens, "\n")), 0700) + if err != nil { + return nil, err + } + var ( pc int64 = 0 stack = NewStack(dataStackCapacity, gas, &err) diff --git a/rpc/result.go b/rpc/result.go index b43d3749f198e0fed2335efaa309c9b3e50d6fce..2e51a2e65f7c205d1b505f771a430d2d54556576 100644 --- a/rpc/result.go +++ b/rpc/result.go @@ -135,6 +135,21 @@ type ResultGetAccount struct { Account *acm.ConcreteAccount } +type AccountHumanReadable struct { + Address acm.Address + PublicKey acm.PublicKey + Sequence uint64 + Balance uint64 + Code []string + StorageRoot string + Permissions []string + Roles []string +} + +type ResultGetAccountHumanReadable struct { + Account *AccountHumanReadable +} + type ResultBroadcastTx struct { txs.Receipt } diff --git a/rpc/service.go b/rpc/service.go index c91e7645ce90ec09fad5236c4267f5b977a14a04..35a2bec61a75c115ba21fb3241d41f7c10caeace 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -27,53 +27,19 @@ import ( "github.com/hyperledger/burrow/logging" "github.com/hyperledger/burrow/logging/structure" logging_types "github.com/hyperledger/burrow/logging/types" + "github.com/hyperledger/burrow/permission" "github.com/hyperledger/burrow/project" "github.com/hyperledger/burrow/txs" tm_types "github.com/tendermint/tendermint/types" + "github.com/tmthrgd/go-hex" ) // Magic! Should probably be configurable, but not shouldn't be so huge we // end up DoSing ourselves. const MaxBlockLookback = 100 -type SubscribableService interface { - // Events - Subscribe(ctx context.Context, subscriptionID string, eventID string, callback func(*ResultEvent) bool) error - Unsubscribe(ctx context.Context, subscriptionID string) error -} - // Base service that provides implementation for all underlying RPC methods -type Service interface { - SubscribableService - // Transact - Transactor() execution.Transactor - // List mempool transactions pass -1 for all unconfirmed transactions - ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, error) - // Status - Status() (*ResultStatus, error) - NetInfo() (*ResultNetInfo, error) - // Accounts - GetAccount(address acm.Address) (*ResultGetAccount, error) - ListAccounts(predicate func(acm.Account) bool) (*ResultListAccounts, error) - GetStorage(address acm.Address, key []byte) (*ResultGetStorage, error) - DumpStorage(address acm.Address) (*ResultDumpStorage, error) - // Blockchain - Genesis() (*ResultGenesis, error) - ChainId() (*ResultChainId, error) - GetBlock(height uint64) (*ResultGetBlock, error) - ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, error) - // Consensus - ListValidators() (*ResultListValidators, error) - DumpConsensusState() (*ResultDumpConsensusState, error) - Peers() (*ResultPeers, error) - // Names - GetName(name string) (*ResultGetName, error) - ListNames(predicate func(*execution.NameRegEntry) bool) (*ResultListNames, error) - // Private keys and signing - GeneratePrivateAccount() (*ResultGeneratePrivateAccount, error) -} - -type service struct { +type Service struct { ctx context.Context state acm.StateIterable subscribable event.Subscribable @@ -84,13 +50,11 @@ type service struct { logger logging_types.InfoTraceLogger } -var _ Service = &service{} - func NewService(ctx context.Context, state acm.StateIterable, nameReg execution.NameRegIterable, subscribable event.Subscribable, blockchain bcm.Blockchain, transactor execution.Transactor, - nodeView query.NodeView, logger logging_types.InfoTraceLogger) *service { + nodeView query.NodeView, logger logging_types.InfoTraceLogger) *Service { - return &service{ + return &Service{ ctx: ctx, state: state, nameReg: nameReg, @@ -103,8 +67,8 @@ func NewService(ctx context.Context, state acm.StateIterable, nameReg execution. } // Provides a sub-service with only the subscriptions methods -func NewSubscribableService(subscribable event.Subscribable, logger logging_types.InfoTraceLogger) *service { - return &service{ +func NewSubscribableService(subscribable event.Subscribable, logger logging_types.InfoTraceLogger) *Service { + return &Service{ ctx: context.Background(), subscribable: subscribable, logger: logger.With(structure.ComponentKey, "Service"), @@ -113,11 +77,11 @@ func NewSubscribableService(subscribable event.Subscribable, logger logging_type // Transacting... -func (s *service) Transactor() execution.Transactor { +func (s *Service) Transactor() execution.Transactor { return s.transactor } -func (s *service) ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, error) { +func (s *Service) ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, error) { // Get all transactions for now transactions, err := s.nodeView.MempoolTransactions(maxTxs) if err != nil { @@ -133,7 +97,7 @@ func (s *service) ListUnconfirmedTxs(maxTxs int) (*ResultListUnconfirmedTxs, err }, nil } -func (s *service) Subscribe(ctx context.Context, subscriptionID string, eventID string, +func (s *Service) Subscribe(ctx context.Context, subscriptionID string, eventID string, callback func(resultEvent *ResultEvent) bool) error { queryBuilder := event.QueryForEventID(eventID) @@ -155,7 +119,7 @@ func (s *service) Subscribe(ctx context.Context, subscriptionID string, eventID }) } -func (s *service) Unsubscribe(ctx context.Context, subscriptionID string) error { +func (s *Service) Unsubscribe(ctx context.Context, subscriptionID string) error { logging.InfoMsg(s.logger, "Unsubscribing from events", "subscription_id", subscriptionID) err := s.subscribable.UnsubscribeAll(ctx, subscriptionID) @@ -165,7 +129,7 @@ func (s *service) Unsubscribe(ctx context.Context, subscriptionID string) error return nil } -func (s *service) Status() (*ResultStatus, error) { +func (s *Service) Status() (*ResultStatus, error) { tip := s.blockchain.Tip() latestHeight := tip.LastBlockHeight() var ( @@ -193,7 +157,7 @@ func (s *service) Status() (*ResultStatus, error) { }, nil } -func (s *service) ChainId() (*ResultChainId, error) { +func (s *Service) ChainId() (*ResultChainId, error) { return &ResultChainId{ ChainName: s.blockchain.GenesisDoc().ChainName, ChainId: s.blockchain.ChainID(), @@ -201,7 +165,7 @@ func (s *service) ChainId() (*ResultChainId, error) { }, nil } -func (s *service) Peers() (*ResultPeers, error) { +func (s *Service) Peers() (*ResultPeers, error) { peers := make([]*Peer, s.nodeView.Peers().Size()) for i, peer := range s.nodeView.Peers().List() { peers[i] = &Peer{ @@ -214,7 +178,7 @@ func (s *service) Peers() (*ResultPeers, error) { }, nil } -func (s *service) NetInfo() (*ResultNetInfo, error) { +func (s *Service) NetInfo() (*ResultNetInfo, error) { listening := s.nodeView.IsListening() listeners := []string{} for _, listener := range s.nodeView.Listeners() { @@ -231,14 +195,14 @@ func (s *service) NetInfo() (*ResultNetInfo, error) { }, nil } -func (s *service) Genesis() (*ResultGenesis, error) { +func (s *Service) Genesis() (*ResultGenesis, error) { return &ResultGenesis{ Genesis: s.blockchain.GenesisDoc(), }, nil } // Accounts -func (s *service) GetAccount(address acm.Address) (*ResultGetAccount, error) { +func (s *Service) GetAccount(address acm.Address) (*ResultGetAccount, error) { acc, err := s.state.GetAccount(address) if err != nil { return nil, err @@ -249,7 +213,7 @@ func (s *service) GetAccount(address acm.Address) (*ResultGetAccount, error) { return &ResultGetAccount{Account: acm.AsConcreteAccount(acc)}, nil } -func (s *service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAccounts, error) { +func (s *Service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAccounts, error) { accounts := make([]*acm.ConcreteAccount, 0) s.state.IterateAccounts(func(account acm.Account) (stop bool) { if predicate(account) { @@ -264,7 +228,7 @@ func (s *service) ListAccounts(predicate func(acm.Account) bool) (*ResultListAcc }, nil } -func (s *service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage, error) { +func (s *Service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage, error) { account, err := s.state.GetAccount(address) if err != nil { return nil, err @@ -283,7 +247,7 @@ func (s *service) GetStorage(address acm.Address, key []byte) (*ResultGetStorage return &ResultGetStorage{Key: key, Value: value.UnpadLeft()}, nil } -func (s *service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) { +func (s *Service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) { account, err := s.state.GetAccount(address) if err != nil { return nil, err @@ -302,8 +266,38 @@ func (s *service) DumpStorage(address acm.Address) (*ResultDumpStorage, error) { }, nil } +func (s *Service) GetAccountHumanReadable(address acm.Address) (*ResultGetAccountHumanReadable, error) { + acc, err := s.state.GetAccount(address) + if err != nil { + return nil, err + } + if acc == nil { + return &ResultGetAccountHumanReadable{}, nil + } + tokens, err := acc.Code().Tokens() + if acc == nil { + return &ResultGetAccountHumanReadable{}, nil + } + perms, err := permission.BasePermissionsToStringList(acc.Permissions().Base) + if acc == nil { + return &ResultGetAccountHumanReadable{}, nil + } + return &ResultGetAccountHumanReadable{ + Account: &AccountHumanReadable{ + Address: acc.Address(), + PublicKey: acc.PublicKey(), + Sequence: acc.Sequence(), + Balance: acc.Balance(), + Code: tokens, + StorageRoot: hex.EncodeUpperToString(acc.StorageRoot()), + Permissions: perms, + Roles: acc.Permissions().Roles, + }, + }, nil +} + // Name registry -func (s *service) GetName(name string) (*ResultGetName, error) { +func (s *Service) GetName(name string) (*ResultGetName, error) { entry, err := s.nameReg.GetNameRegEntry(name) if err != nil { return nil, err @@ -314,7 +308,7 @@ func (s *service) GetName(name string) (*ResultGetName, error) { return &ResultGetName{Entry: entry}, nil } -func (s *service) ListNames(predicate func(*execution.NameRegEntry) bool) (*ResultListNames, error) { +func (s *Service) ListNames(predicate func(*execution.NameRegEntry) bool) (*ResultListNames, error) { var names []*execution.NameRegEntry s.nameReg.IterateNameRegEntries(func(entry *execution.NameRegEntry) (stop bool) { if predicate(entry) { @@ -328,7 +322,7 @@ func (s *service) ListNames(predicate func(*execution.NameRegEntry) bool) (*Resu }, nil } -func (s *service) GetBlock(height uint64) (*ResultGetBlock, error) { +func (s *Service) GetBlock(height uint64) (*ResultGetBlock, error) { return &ResultGetBlock{ Block: s.nodeView.BlockStore().LoadBlock(int64(height)), BlockMeta: s.nodeView.BlockStore().LoadBlockMeta(int64(height)), @@ -340,7 +334,7 @@ func (s *service) GetBlock(height uint64) (*ResultGetBlock, error) { // from the top of the range of blocks. // Passing 0 for maxHeight sets the upper height of the range to the current // blockchain height. -func (s *service) ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, error) { +func (s *Service) ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, error) { latestHeight := s.blockchain.Tip().LastBlockHeight() if minHeight == 0 { @@ -365,7 +359,7 @@ func (s *service) ListBlocks(minHeight, maxHeight uint64) (*ResultListBlocks, er }, nil } -func (s *service) ListValidators() (*ResultListValidators, error) { +func (s *Service) ListValidators() (*ResultListValidators, error) { // TODO: when we reintroduce support for bonding and unbonding update this // to reflect the mutable bonding state validators := s.blockchain.Validators() @@ -380,7 +374,7 @@ func (s *service) ListValidators() (*ResultListValidators, error) { }, nil } -func (s *service) DumpConsensusState() (*ResultDumpConsensusState, error) { +func (s *Service) DumpConsensusState() (*ResultDumpConsensusState, error) { peerRoundState, err := s.nodeView.PeerRoundStates() if err != nil { return nil, err @@ -391,7 +385,7 @@ func (s *service) DumpConsensusState() (*ResultDumpConsensusState, error) { }, nil } -func (s *service) GeneratePrivateAccount() (*ResultGeneratePrivateAccount, error) { +func (s *Service) GeneratePrivateAccount() (*ResultGeneratePrivateAccount, error) { privateAccount, err := acm.GeneratePrivateAccount() if err != nil { return nil, err diff --git a/rpc/tm/methods.go b/rpc/tm/methods.go index 7da5d22b553dba8d0a91746a1b853da5522ac267..48ca428a0476378bc013858203c529f2851d5423 100644 --- a/rpc/tm/methods.go +++ b/rpc/tm/methods.go @@ -18,6 +18,7 @@ import ( // Method names const ( + BroadcastTx = "broadcast_tx" Subscribe = "subscribe" Unsubscribe = "unsubscribe" @@ -26,10 +27,11 @@ const ( NetInfo = "net_info" // Accounts - ListAccounts = "list_accounts" - GetAccount = "get_account" - GetStorage = "get_storage" - DumpStorage = "dump_storage" + ListAccounts = "list_accounts" + GetAccount = "get_account" + GetStorage = "get_storage" + DumpStorage = "dump_storage" + GetAccountHuman = "get_account_human" // Simulated call Call = "call" @@ -38,7 +40,6 @@ const ( // Names GetName = "get_name" ListNames = "list_names" - BroadcastTx = "broadcast_tx" // Blockchain Genesis = "genesis" @@ -58,7 +59,7 @@ const ( const SubscriptionTimeoutSeconds = 5 * time.Second -func GetRoutes(service rpc.Service, logger logging_types.InfoTraceLogger) map[string]*gorpc.RPCFunc { +func GetRoutes(service *rpc.Service, logger logging_types.InfoTraceLogger) map[string]*gorpc.RPCFunc { logger = logging.WithScope(logger, "GetRoutes") return map[string]*gorpc.RPCFunc{ // Transact @@ -146,9 +147,10 @@ func GetRoutes(service rpc.Service, logger logging_types.InfoTraceLogger) map[st }) }, ""), - GetAccount: gorpc.NewRPCFunc(service.GetAccount, "address"), - GetStorage: gorpc.NewRPCFunc(service.GetStorage, "address,key"), - DumpStorage: gorpc.NewRPCFunc(service.DumpStorage, "address"), + GetAccount: gorpc.NewRPCFunc(service.GetAccount, "address"), + GetStorage: gorpc.NewRPCFunc(service.GetStorage, "address,key"), + DumpStorage: gorpc.NewRPCFunc(service.DumpStorage, "address"), + GetAccountHuman: gorpc.NewRPCFunc(service.GetAccountHumanReadable, "address"), // Blockchain Genesis: gorpc.NewRPCFunc(service.Genesis, ""), diff --git a/rpc/tm/server.go b/rpc/tm/server.go index 25f5f5cd8baae698fa74d7ab53af6290e6d2604c..e6ede8a34869c333c354e6a41768e78a2a20a9bd 100644 --- a/rpc/tm/server.go +++ b/rpc/tm/server.go @@ -26,7 +26,7 @@ import ( "github.com/tendermint/tendermint/rpc/lib/server" ) -func StartServer(service rpc.Service, pattern, listenAddress string, emitter event.Emitter, +func StartServer(service *rpc.Service, pattern, listenAddress string, emitter event.Emitter, logger logging_types.InfoTraceLogger) (net.Listener, error) { logger = logger.With(structure.ComponentKey, "RPC_TM") diff --git a/rpc/v0/json_service.go b/rpc/v0/json_service.go index 50cad08a41326059d6cd6838d74ee3aab2b49eea..223e927daea4e5a83dfc469fb6a6a390fe20be11 100644 --- a/rpc/v0/json_service.go +++ b/rpc/v0/json_service.go @@ -82,14 +82,14 @@ func (jrs *JsonRpcServer) handleFunc(c *gin.Context) { // Used for Burrow. Implements server.HttpService type JSONService struct { codec rpc.Codec - service rpc.Service + service *rpc.Service eventSubs *Subscriptions defaultHandlers map[string]RequestHandlerFunc logger logging_types.InfoTraceLogger } // Create a new JSON-RPC 2.0 service for burrow (tendermint). -func NewJSONService(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) server.HttpService { +func NewJSONService(codec rpc.Codec, service *rpc.Service, logger logging_types.InfoTraceLogger) server.HttpService { tmhttps := &JSONService{ codec: codec, diff --git a/rpc/v0/methods.go b/rpc/v0/methods.go index aa4416b998757c5adc72856ea0c38ba380b04080..e3925f8b496d16e8817b5c448f5da6d7461f9d18 100644 --- a/rpc/v0/methods.go +++ b/rpc/v0/methods.go @@ -63,7 +63,7 @@ const ( type RequestHandlerFunc func(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) // Private. Create a method name -> method handler map. -func GetMethods(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) map[string]RequestHandlerFunc { +func GetMethods(codec rpc.Codec, service *rpc.Service, logger logging_types.InfoTraceLogger) map[string]RequestHandlerFunc { accountFilterFactory := filters.NewAccountFilterFactory() nameRegFilterFactory := filters.NewNameRegFilterFactory() diff --git a/rpc/v0/subscriptions.go b/rpc/v0/subscriptions.go index dbfab6f76fd6ef83e48dce613e0154f0c62da146..8bb91864790cfc3d08c6d790c5da96ca0ed2a2ec 100644 --- a/rpc/v0/subscriptions.go +++ b/rpc/v0/subscriptions.go @@ -62,12 +62,12 @@ func (subsCache *SubscriptionsCache) poll() []interface{} { // Catches events that callers subscribe to and adds them to an array ready to be polled. type Subscriptions struct { mtx *sync.RWMutex - service rpc.Service + service *rpc.Service subs map[string]*SubscriptionsCache reap bool } -func NewSubscriptions(service rpc.Service) *Subscriptions { +func NewSubscriptions(service *rpc.Service) *Subscriptions { es := &Subscriptions{ mtx: &sync.RWMutex{}, service: service, diff --git a/rpc/v0/websocket_service.go b/rpc/v0/websocket_service.go index 17b84e4409b54ed63d4db14c0a85217f7d02283a..8c3c5e5d3138e9faf20eeed87e36eaaa085a19d4 100644 --- a/rpc/v0/websocket_service.go +++ b/rpc/v0/websocket_service.go @@ -30,13 +30,13 @@ import ( // Used for Burrow. Implements WebSocketService. type WebsocketService struct { codec rpc.Codec - service rpc.Service + service *rpc.Service defaultHandlers map[string]RequestHandlerFunc logger logging_types.InfoTraceLogger } // Create a new websocket service. -func NewWebsocketService(codec rpc.Codec, service rpc.Service, logger logging_types.InfoTraceLogger) server.WebSocketService { +func NewWebsocketService(codec rpc.Codec, service *rpc.Service, logger logging_types.InfoTraceLogger) server.WebSocketService { tmwss := &WebsocketService{ codec: codec, service: service,