-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
abi_codec.go
106 lines (94 loc) · 2.95 KB
/
abi_codec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package encoding
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/pkg/errors"
)
type ReportCodec struct {
reportTypes abi.Arguments
}
func getReportTypes() (abi.Arguments, error) {
bytes32ArrType, err := abi.NewType("bytes32[]", "", []abi.ArgumentMarshaling{})
if err != nil {
return nil, fmt.Errorf("unable to create an ABI type object for bytes32[]")
}
bytesArrType, err := abi.NewType("bytes[]", "", []abi.ArgumentMarshaling{})
if err != nil {
return nil, fmt.Errorf("unable to create an ABI type object for bytes[]")
}
return abi.Arguments([]abi.Argument{
{Name: "ids", Type: bytes32ArrType},
{Name: "results", Type: bytesArrType},
{Name: "errors", Type: bytesArrType},
}), nil
}
func NewReportCodec() (*ReportCodec, error) {
reportTypes, err := getReportTypes()
if err != nil {
return nil, err
}
return &ReportCodec{
reportTypes: reportTypes,
}, nil
}
func SliceToByte32(slice []byte) ([32]byte, error) {
if len(slice) != 32 {
return [32]byte{}, fmt.Errorf("input length is not 32 bytes: %d", len(slice))
}
var res [32]byte
copy(res[:], slice[:32])
return res, nil
}
func (c *ReportCodec) EncodeReport(requests []*ProcessedRequest) ([]byte, error) {
size := len(requests)
if size == 0 {
return []byte{}, nil
}
ids := make([][32]byte, size)
results := make([][]byte, size)
errors := make([][]byte, size)
for i := 0; i < size; i++ {
var err error
ids[i], err = SliceToByte32(requests[i].RequestID)
if err != nil {
return nil, err
}
results[i] = requests[i].Result
errors[i] = requests[i].Error
}
return c.reportTypes.Pack(ids, results, errors)
}
func (c *ReportCodec) DecodeReport(raw []byte) ([]*ProcessedRequest, error) {
reportElems := map[string]interface{}{}
if err := c.reportTypes.UnpackIntoMap(reportElems, raw); err != nil {
return nil, errors.WithMessage(err, "unable to unpack elements from raw report")
}
idsIface, idsOK := reportElems["ids"]
resultsIface, resultsOK := reportElems["results"]
errorsIface, errorsOK := reportElems["errors"]
if !idsOK || !resultsOK || !errorsOK {
return nil, fmt.Errorf("missing arrays in raw report, ids: %v, results: %v, errors: %v", idsOK, resultsOK, errorsOK)
}
ids, idsOK := idsIface.([][32]byte)
results, resultsOK := resultsIface.([][]byte)
errors, errorsOK := errorsIface.([][]byte)
if !idsOK || !resultsOK || !errorsOK {
return nil, fmt.Errorf("unable to cast part of raw report into array type, ids: %v, results: %v, errors: %v", idsOK, resultsOK, errorsOK)
}
size := len(ids)
if len(results) != size || len(errors) != size {
return nil, fmt.Errorf("unequal sizes of arrays parsed from raw report, ids: %v, results: %v, errors: %v", len(ids), len(results), len(errors))
}
if size == 0 {
return []*ProcessedRequest{}, nil
}
decoded := make([]*ProcessedRequest, size)
for i := 0; i < size; i++ {
decoded[i] = &ProcessedRequest{
RequestID: ids[i][:],
Result: results[i],
Error: errors[i],
}
}
return decoded, nil
}