From e2f42e92a094fab583173b44b47300abf1b48814 Mon Sep 17 00:00:00 2001 From: dauTT <30392990+dauTT@users.noreply.github.com> Date: Mon, 26 Nov 2018 22:12:33 +0100 Subject: [PATCH] Implemented rcp method GetAssetState (#103) * Fix missing dot in configPath * Add rpc GetAssetState method * Update rpc README.md * Update version to 0.45.10 --- VERSION | 2 +- cli/server/server.go | 2 +- pkg/core/asset_state.go | 21 +++++++++++++++ pkg/core/blockchain.go | 15 +++++++++++ pkg/core/blockchainer.go | 5 +++- pkg/crypto/elliptic_curve.go | 4 +-- pkg/network/helper_test.go | 3 +++ pkg/rpc/README.md | 2 +- pkg/rpc/server.go | 28 +++++++++++++++++++- pkg/rpc/wrappers/asset_state.go | 45 +++++++++++++++++++++++++++++++++ 10 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 pkg/rpc/wrappers/asset_state.go diff --git a/VERSION b/VERSION index a9cce3e09..a1cf49f6e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.44.11 +0.45.11 diff --git a/cli/server/server.go b/cli/server/server.go index 20d71141f..2e8227ea4 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -40,7 +40,7 @@ func startServer(ctx *cli.Context) error { net = config.ModeMainNet } - configPath := "./config" + configPath := "../config" if argCp := ctx.String("config-path"); argCp != "" { configPath = argCp } diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index fff5e6992..987001fff 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -38,6 +38,7 @@ type AssetState struct { Available util.Fixed8 Precision uint8 FeeMode uint8 + FeeAddress util.Uint160 Owner *crypto.PublicKey Admin util.Uint160 Issuer util.Uint160 @@ -72,6 +73,9 @@ func (a *AssetState) DecodeBinary(r io.Reader) error { if err := binary.Read(r, binary.LittleEndian, &a.FeeMode); err != nil { return err } + if err := binary.Read(r, binary.LittleEndian, &a.FeeAddress); err != nil { + return err + } a.Owner = &crypto.PublicKey{} if err := a.Owner.DecodeBinary(r); err != nil { @@ -115,6 +119,11 @@ func (a *AssetState) EncodeBinary(w io.Writer) error { if err := binary.Write(w, binary.LittleEndian, a.FeeMode); err != nil { return err } + + if err := binary.Write(w, binary.LittleEndian, a.FeeAddress); err != nil { + return err + } + if err := a.Owner.EncodeBinary(w); err != nil { return err } @@ -129,3 +138,15 @@ func (a *AssetState) EncodeBinary(w io.Writer) error { } return binary.Write(w, binary.LittleEndian, a.IsFrozen) } + +// Get the asset name based on its type. +func (a *AssetState) GetName() string { + + if a.AssetType == transaction.GoverningToken { + return "NEO" + } else if a.AssetType == transaction.UtilityToken { + return "NEOGas" + } + + return a.Name +} diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index fc742b079..83e8c5c41 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -8,6 +8,7 @@ import ( "time" "github.com/CityOfZion/neo-go/config" + //"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/util" @@ -527,6 +528,20 @@ func (bc *Blockchain) HeaderHeight() uint32 { return uint32(bc.headerListLen() - 1) } +func (bc *Blockchain) GetAssetState(assetID util.Uint256) *AssetState { + + var as *AssetState + bc.Store.Seek(storage.STAsset.Bytes(), func(k, v []byte) { + var a AssetState + a.DecodeBinary(bytes.NewReader(v)) + if a.ID == assetID { + as = &a + } + }) + + return as +} + func hashAndIndexToBytes(h util.Uint256, index uint32) []byte { buf := make([]byte, 4) binary.LittleEndian.PutUint32(buf, index) diff --git a/pkg/core/blockchainer.go b/pkg/core/blockchainer.go index 2d4d8c8f6..d965547d1 100644 --- a/pkg/core/blockchainer.go +++ b/pkg/core/blockchainer.go @@ -1,6 +1,8 @@ package core -import "github.com/CityOfZion/neo-go/pkg/util" +import ( + "github.com/CityOfZion/neo-go/pkg/util" +) // Blockchainer is an interface that abstract the implementation // of the blockchain. @@ -15,4 +17,5 @@ type Blockchainer interface { CurrentBlockHash() util.Uint256 HasBlock(util.Uint256) bool HasTransaction(util.Uint256) bool + GetAssetState(util.Uint256) *AssetState } diff --git a/pkg/crypto/elliptic_curve.go b/pkg/crypto/elliptic_curve.go index 6a42d1167..7868a597a 100644 --- a/pkg/crypto/elliptic_curve.go +++ b/pkg/crypto/elliptic_curve.go @@ -138,11 +138,11 @@ func (p ECPoint) EncodeBinary(w io.Writer) error { // String implements the Stringer interface. func (p *ECPoint) String() string { if p.IsInfinity() { - return "(inf, inf)" + return "00" } bx := hex.EncodeToString(p.X.Bytes()) by := hex.EncodeToString(p.Y.Bytes()) - return fmt.Sprintf("(%s, %s)", bx, by) + return fmt.Sprintf("%s%s", bx, by) } // IsInfinity checks if point P is infinity on EllipticCurve ec. diff --git a/pkg/network/helper_test.go b/pkg/network/helper_test.go index 8d3c6c7a1..39de8211b 100644 --- a/pkg/network/helper_test.go +++ b/pkg/network/helper_test.go @@ -29,6 +29,9 @@ func (chain testChain) GetBlock(hash util.Uint256) (*core.Block, error) { func (chain testChain) GetHeaderHash(int) util.Uint256 { return util.Uint256{} } +func (chain testChain) GetAssetState(util.Uint256) *core.AssetState { + return nil +} func (chain testChain) CurrentHeaderHash() util.Uint256 { return util.Uint256{} } diff --git a/pkg/rpc/README.md b/pkg/rpc/README.md index af2af07eb..a90cbac1a 100644 --- a/pkg/rpc/README.md +++ b/pkg/rpc/README.md @@ -101,7 +101,7 @@ which would yield the response: | `submitblock` | No | Needs to be implemented in `pkg/core/blockchain.go` | | `gettxout` | No | Needs to be implemented in `pkg/core/blockchain.go` | | `invoke` | No | VM | -| `getassetstate` | No | Needs to be implemented in `pkg/core/blockchain.go` | +| `getassetstate` | Yes |-| | `getpeers` | Yes | - | | `getversion` | Yes | - | | `getconnectioncount` | Yes | - | diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index 9c9180add..2ef58faf6 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -179,9 +179,35 @@ Methods: results = peers - case "validateaddress", "getblocksysfee", "getcontractstate", "getrawmempool", "getrawtransaction", "getstorage", "submitblock", "gettxout", "invoke", "invokefunction", "invokescript", "sendrawtransaction", "getaccountstate", "getassetstate": + case "validateaddress", "getblocksysfee", "getcontractstate", "getrawmempool", "getrawtransaction", "getstorage", "submitblock", "gettxout", "invoke", "invokefunction", "invokescript", "sendrawtransaction", "getaccountstate": results = "TODO" + case "getassetstate": + var err error + + param, exists := reqParams.ValueAt(0) + if !exists { + err = errors.New("Param at index at 0 doesn't exist") + resultsErr = NewInvalidParamsError(err.Error(), err) + break + } + + if param.Type != "string" { + err = errors.New("Param need to be a string") + resultsErr = NewInvalidParamsError(err.Error(), err) + break + } + + paramAssetID, err := util.Uint256DecodeString(param.StringVal) + + as := s.chain.GetAssetState(paramAssetID) + + if as != nil { + results = wrappers.NewAssetState(as) + } else { + results = "Invalid assetid" + } + default: resultsErr = NewMethodNotFoundError(fmt.Sprintf("Method '%s' not supported", req.Method), nil) } diff --git a/pkg/rpc/wrappers/asset_state.go b/pkg/rpc/wrappers/asset_state.go new file mode 100644 index 000000000..f4e32e33b --- /dev/null +++ b/pkg/rpc/wrappers/asset_state.go @@ -0,0 +1,45 @@ +package wrappers + +import ( + "github.com/CityOfZion/neo-go/pkg/core" + "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/util" +) + +// AssetState wrapper used for the representation of +// core.AssetState on the RPC Server. +type AssetState struct { + ID util.Uint256 `json:"assetId"` + AssetType transaction.AssetType `json:"assetType"` + Name string `json:"name"` + Amount util.Fixed8 `json:"amount"` + Available util.Fixed8 `json:"available"` + Precision uint8 `json:"precision"` + FeeMode uint8 `json:"fee"` + FeeAddress util.Uint160 `json:"address"` + Owner string `json:"owner"` + Admin string `json:"admin"` + Issuer string `json:"issuer"` + Expiration uint32 `json:"expiration"` + IsFrozen bool `json:"is_frozen"` +} + +// NewAssetState creates a new AssetState wrapper. +func NewAssetState(a *core.AssetState) AssetState { + return AssetState{ + ID: a.ID, + AssetType: a.AssetType, + Name: a.GetName(), + Amount: a.Amount, + Available: a.Available, + Precision: a.Precision, + FeeMode: a.FeeMode, + FeeAddress: a.FeeAddress, + Owner: a.Owner.String(), + Admin: crypto.AddressFromUint160(a.Admin), + Issuer: crypto.AddressFromUint160(a.Issuer), + Expiration: a.Expiration, + IsFrozen: a.IsFrozen, + } +}