rpc/client: add support for notification filters

Differing a bit from #895 draft specification, we won't add `sender` or
`cosigner` to `transaction_executed`.
This commit is contained in:
Roman Khimov 2020-05-13 13:16:42 +03:00
parent c4c080d240
commit 725b47ddef
4 changed files with 283 additions and 42 deletions

View file

@ -29,6 +29,29 @@ type (
Type smartcontract.ParamType `json:"type"`
Value Param `json:"value"`
}
// BlockFilter is a wrapper structure for block event filter. The only
// allowed filter is primary index.
BlockFilter struct {
Primary int `json:"primary"`
}
// TxFilter is a wrapper structure for transaction event filter. It
// allows to filter transactions by senders and cosigners.
TxFilter struct {
Sender *util.Uint160 `json:"sender,omitempty"`
Cosigner *util.Uint160 `json:"cosigner,omitempty"`
}
// NotificationFilter is a wrapper structure representing filter used for
// notifications generated during transaction execution. Notifications can
// only be filtered by contract hash.
NotificationFilter struct {
Contract util.Uint160 `json:"contract"`
}
// ExecutionFilter is a wrapper structure used for transaction execution
// events. It allows to choose failing or successful transactions based
// on their VM state.
ExecutionFilter struct {
State string `json:"state"`
}
)
// These are parameter types accepted by RPC server.
@ -38,6 +61,10 @@ const (
NumberT
ArrayT
FuncParamT
BlockFilterT
TxFilterT
NotificationFilterT
ExecutionFilterT
)
func (p Param) String() string {
@ -130,38 +157,46 @@ func (p Param) GetBytesHex() ([]byte, error) {
// UnmarshalJSON implements json.Unmarshaler interface.
func (p *Param) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
p.Type = StringT
p.Value = s
return nil
}
var num float64
if err := json.Unmarshal(data, &num); err == nil {
p.Type = NumberT
p.Value = int(num)
return nil
// To unmarshal correctly we need to pass pointers into the decoder.
var attempts = [...]Param{
{NumberT, &num},
{StringT, &s},
{FuncParamT, &FuncParam{}},
{BlockFilterT, &BlockFilter{}},
{TxFilterT, &TxFilter{}},
{NotificationFilterT, &NotificationFilter{}},
{ExecutionFilterT, &ExecutionFilter{}},
{ArrayT, &[]Param{}},
}
r := bytes.NewReader(data)
jd := json.NewDecoder(r)
jd.DisallowUnknownFields()
var fp FuncParam
if err := jd.Decode(&fp); err == nil {
p.Type = FuncParamT
p.Value = fp
return nil
}
var ps []Param
if err := json.Unmarshal(data, &ps); err == nil {
p.Type = ArrayT
p.Value = ps
return nil
for _, cur := range attempts {
r := bytes.NewReader(data)
jd := json.NewDecoder(r)
jd.DisallowUnknownFields()
if err := jd.Decode(cur.Value); err == nil {
p.Type = cur.Type
// But we need to store actual values, not pointers.
switch val := cur.Value.(type) {
case *float64:
p.Value = int(*val)
case *string:
p.Value = *val
case *FuncParam:
p.Value = *val
case *BlockFilter:
p.Value = *val
case *TxFilter:
p.Value = *val
case *NotificationFilter:
p.Value = *val
case *ExecutionFilter:
p.Value = *val
case *[]Param:
p.Value = *val
}
return nil
}
}
return errors.New("unknown type")