neoneo-go/pkg/neorpc/types.go
2023-03-16 23:43:00 +03:00

144 lines
4.8 KiB
Go

/*
Package neorpc contains a set of types used for JSON-RPC communication with Neo servers.
It defines basic request/response types as well as a set of errors and additional
parameters used for specific requests/responses.
*/
package neorpc
import (
"encoding/json"
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/util"
)
const (
// JSONRPCVersion is the only JSON-RPC protocol version supported.
JSONRPCVersion = "2.0"
)
type (
// Request represents JSON-RPC request. It's generic enough to be used in many
// generic JSON-RPC communication scenarios, yet at the same time it's
// tailored for NeoGo RPC Client needs.
Request struct {
// JSONRPC is the protocol version, only valid when it contains JSONRPCVersion.
JSONRPC string `json:"jsonrpc"`
// Method is the method being called.
Method string `json:"method"`
// Params is a set of method-specific parameters passed to the call. They
// can be anything as long as they can be marshaled to JSON correctly and
// used by the method implementation on the server side. While JSON-RPC
// technically allows it to be an object, all Neo calls expect params
// to be an array.
Params []interface{} `json:"params"`
// ID is an identifier associated with this request. JSON-RPC itself allows
// any strings to be used for it as well, but NeoGo RPC client uses numeric
// identifiers.
ID uint64 `json:"id"`
}
// Header is a generic JSON-RPC 2.0 response header (ID and JSON-RPC version).
Header struct {
ID json.RawMessage `json:"id"`
JSONRPC string `json:"jsonrpc"`
}
// HeaderAndError adds an Error (that can be empty) to the Header, it's used
// to construct type-specific responses.
HeaderAndError struct {
Header
Error *Error `json:"error,omitempty"`
}
// Raw represents a standard raw JSON-RPC 2.0
// response: http://www.jsonrpc.org/specification#response_object.
Response struct {
HeaderAndError
Result json.RawMessage `json:"result,omitempty"`
}
// Notification is a type used to represent wire format of events, they're
// special in that they look like requests but they don't have IDs and their
// "method" is actually an event name.
Notification struct {
JSONRPC string `json:"jsonrpc"`
Event EventID `json:"method"`
Payload []interface{} `json:"params"`
}
// SignerWithWitness represents transaction's signer with the corresponding witness.
SignerWithWitness struct {
transaction.Signer
transaction.Witness
}
)
// signerWithWitnessAux is an auxiliary struct for JSON marshalling. We need it because of
// DisallowUnknownFields JSON marshaller setting.
type signerWithWitnessAux struct {
Account string `json:"account"`
Scopes transaction.WitnessScope `json:"scopes"`
AllowedContracts []util.Uint160 `json:"allowedcontracts,omitempty"`
AllowedGroups []*keys.PublicKey `json:"allowedgroups,omitempty"`
Rules []transaction.WitnessRule `json:"rules,omitempty"`
InvocationScript []byte `json:"invocation,omitempty"`
VerificationScript []byte `json:"verification,omitempty"`
}
// MarshalJSON implements the json.Marshaler interface.
func (s *SignerWithWitness) MarshalJSON() ([]byte, error) {
signer := &signerWithWitnessAux{
Account: s.Account.StringLE(),
Scopes: s.Scopes,
AllowedContracts: s.AllowedContracts,
AllowedGroups: s.AllowedGroups,
Rules: s.Rules,
InvocationScript: s.InvocationScript,
VerificationScript: s.VerificationScript,
}
return json.Marshal(signer)
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (s *SignerWithWitness) UnmarshalJSON(data []byte) error {
aux := new(signerWithWitnessAux)
err := json.Unmarshal(data, aux)
if err != nil {
return fmt.Errorf("not a signer: %w", err)
}
acc, err := util.Uint160DecodeStringLE(strings.TrimPrefix(aux.Account, "0x"))
if err != nil {
acc, err = address.StringToUint160(aux.Account)
}
if err != nil {
return fmt.Errorf("not a signer: %w", err)
}
s.Signer = transaction.Signer{
Account: acc,
Scopes: aux.Scopes,
AllowedContracts: aux.AllowedContracts,
AllowedGroups: aux.AllowedGroups,
Rules: aux.Rules,
}
s.Witness = transaction.Witness{
InvocationScript: aux.InvocationScript,
VerificationScript: aux.VerificationScript,
}
return nil
}
// EventID implements EventContainer interface and returns notification ID.
func (n *Notification) EventID() EventID {
return n.Event
}
// EventPayload implements EventContainer interface and returns notification
// object.
func (n *Notification) EventPayload() interface{} {
return n.Payload[0]
}