oracle: implement filters
This commit is contained in:
parent
e4528e59dc
commit
c420014cb5
6 changed files with 113 additions and 0 deletions
1
go.mod
1
go.mod
|
@ -1,6 +1,7 @@
|
||||||
module github.com/nspcc-dev/neo-go
|
module github.com/nspcc-dev/neo-go
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/PaesslerAG/jsonpath v0.1.1
|
||||||
github.com/Workiva/go-datastructures v1.0.50
|
github.com/Workiva/go-datastructures v1.0.50
|
||||||
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db
|
||||||
github.com/alicebob/miniredis v2.5.0+incompatible
|
github.com/alicebob/miniredis v2.5.0+incompatible
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -8,6 +8,11 @@ github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
|
||||||
|
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
|
||||||
|
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
||||||
|
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
|
||||||
|
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
|
||||||
github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=
|
github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=
|
||||||
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
|
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
|
||||||
github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw=
|
github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw=
|
||||||
|
|
|
@ -140,6 +140,10 @@ func TestOracle(t *testing.T) {
|
||||||
putOracleRequest(t, cs.Hash, bc, "http://get.maxallowed", nil, "handle", []byte{}, 10_000_000)
|
putOracleRequest(t, cs.Hash, bc, "http://get.maxallowed", nil, "handle", []byte{}, 10_000_000)
|
||||||
putOracleRequest(t, cs.Hash, bc, "http://get.maxallowed", nil, "handle", []byte{}, 100_000_000)
|
putOracleRequest(t, cs.Hash, bc, "http://get.maxallowed", nil, "handle", []byte{}, 100_000_000)
|
||||||
|
|
||||||
|
flt := "Values[1]"
|
||||||
|
putOracleRequest(t, cs.Hash, bc, "http://get.filter", &flt, "handle", []byte{}, 10_000_000)
|
||||||
|
putOracleRequest(t, cs.Hash, bc, "http://get.filterinv", &flt, "handle", []byte{}, 10_000_000)
|
||||||
|
|
||||||
checkResp := func(t *testing.T, id uint64, resp *transaction.OracleResponse) *state.OracleRequest {
|
checkResp := func(t *testing.T, id uint64, resp *transaction.OracleResponse) *state.OracleRequest {
|
||||||
req, err := oracleCtr.GetRequestInternal(bc.dao, id)
|
req, err := oracleCtr.GetRequestInternal(bc.dao, id)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -242,6 +246,19 @@ func TestOracle(t *testing.T) {
|
||||||
Result: make([]byte, transaction.MaxOracleResultSize),
|
Result: make([]byte, transaction.MaxOracleResultSize),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("WithFilter", func(t *testing.T) {
|
||||||
|
checkResp(t, 10, &transaction.OracleResponse{
|
||||||
|
ID: 10,
|
||||||
|
Code: transaction.Success,
|
||||||
|
Result: []byte(`[2]`),
|
||||||
|
})
|
||||||
|
t.Run("invalid response", func(t *testing.T) {
|
||||||
|
checkResp(t, 11, &transaction.OracleResponse{
|
||||||
|
ID: 11,
|
||||||
|
Code: transaction.Error,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOracleFull(t *testing.T) {
|
func TestOracleFull(t *testing.T) {
|
||||||
|
@ -354,6 +371,14 @@ func newDefaultHTTPClient() oracle.HTTPClient {
|
||||||
code: http.StatusOK,
|
code: http.StatusOK,
|
||||||
body: make([]byte, transaction.MaxOracleResultSize),
|
body: make([]byte, transaction.MaxOracleResultSize),
|
||||||
},
|
},
|
||||||
|
"http://get.filter": {
|
||||||
|
code: http.StatusOK,
|
||||||
|
body: []byte(`{"Values":["one", 2, 3],"Another":null}`),
|
||||||
|
},
|
||||||
|
"http://get.filterinv": {
|
||||||
|
code: http.StatusOK,
|
||||||
|
body: []byte{0xFF},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
24
pkg/services/oracle/filter.go
Normal file
24
pkg/services/oracle/filter.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package oracle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/PaesslerAG/jsonpath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func filter(value []byte, path string) ([]byte, error) {
|
||||||
|
if !utf8.Valid(value) {
|
||||||
|
return nil, errors.New("not an UTF-8")
|
||||||
|
}
|
||||||
|
var v interface{}
|
||||||
|
if err := json.Unmarshal(value, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, err := jsonpath.Get(path, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.Marshal([]interface{}{result})
|
||||||
|
}
|
50
pkg/services/oracle/filter_test.go
Normal file
50
pkg/services/oracle/filter_test.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package oracle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
js := `{
|
||||||
|
"Stores": [ "Lambton Quay", "Willis Street" ],
|
||||||
|
"Manufacturers": [
|
||||||
|
{
|
||||||
|
"Name": "Acme Co",
|
||||||
|
"Products": [
|
||||||
|
{ "Name": "Anvil", "Price": 50 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Contoso",
|
||||||
|
"Products": [
|
||||||
|
{ "Name": "Elbow Grease", "Price": 99.95 },
|
||||||
|
{ "Name": "Headlight Fluid", "Price": 4 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
result, path string
|
||||||
|
}{
|
||||||
|
{`["Acme Co"]`, "Manufacturers[0].Name"},
|
||||||
|
{`[50]`, "Manufacturers[0].Products[0].Price"},
|
||||||
|
{`["Elbow Grease"]`, "Manufacturers[1].Products[0].Name"},
|
||||||
|
{`[{"Name":"Elbow Grease","Price":99.95}]`, "Manufacturers[1].Products[0]"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.path, func(t *testing.T) {
|
||||||
|
actual, err := filter([]byte(js), tc.path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.result, string(actual))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("not an UTF-8", func(t *testing.T) {
|
||||||
|
_, err := filter([]byte{0xFF}, "Manufacturers[0].Name")
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
|
@ -115,6 +115,14 @@ func (o *Oracle) processRequest(priv *keys.PrivateKey, req request) error {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if req.Req.Filter != nil {
|
||||||
|
res, err := filter(result, *req.Req.Filter)
|
||||||
|
if err != nil {
|
||||||
|
resp.Code = transaction.Error
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = res
|
||||||
|
}
|
||||||
resp.Code = transaction.Success
|
resp.Code = transaction.Success
|
||||||
resp.Result = result
|
resp.Result = result
|
||||||
case r.StatusCode == http.StatusForbidden:
|
case r.StatusCode == http.StatusForbidden:
|
||||||
|
|
Loading…
Reference in a new issue