diff --git a/internal/server/helpers.go b/internal/server/helpers.go index b34bbfc..95ea78d 100644 --- a/internal/server/helpers.go +++ b/internal/server/helpers.go @@ -1,9 +1,6 @@ package server import ( - "fmt" - "reflect" - "github.com/shufflingpixels/antelope-go/ship" ) @@ -28,123 +25,3 @@ func toActionTraceV1(trace *ship.ActionTrace) *ship.ActionTraceV1 { } return trace.V1 } - -func isVariantName(name string) bool { - validVariants := []string{ - "get_status_request_v0", - "block_position", - "get_status_result_v0", - "get_blocks_request_v0", - "get_blocks_ack_request_v0", - "get_blocks_result_v0", - "row", - "table_delta_v0", - "action", - "account_auth_sequence", - "action_receipt_v0", - "account_delta", - "action_trace_v0", - "partial_transaction_v0", - "transaction_trace_v0", - "packed_transaction", - "transaction_receipt_header", - "transaction_receipt", - "extension", - "block_header", - "signed_block_header", - "signed_block", - "transaction_header", - "transaction", - "code_id", - "account_v0", - "account_metadata_v0", - "code_v0", - "contract_table_v0", - "contract_row_v0", - "contract_index64_v0", - "contract_index128_v0", - "contract_index256_v0", - "contract_index_double_v0", - "contract_index_long_double_v0", - "producer_key", - "producer_schedule", - "block_signing_authority_v0", - "producer_authority", - "producer_authority_schedule", - "chain_config_v0", - "global_property_v0", - "global_property_v1", - "generated_transaction_v0", - "activated_protocol_feature_v0", - "protocol_state_v0", - "key_weight", - "permission_level", - "permission_level_weight", - "wait_weight", - "authority", - "permission_v0", - "permission_link_v0", - "resource_limits_v0", - "usage_accumulator_v0", - "resource_usage_v0", - "resource_limits_state_v0", - "resource_limits_ratio_v0", - "elastic_limit_parameters_v0", - "resource_limits_config_v0", - } - - for _, v := range validVariants { - if v == name { - return true - } - } - return false -} - -// Check if a structure is a variant type. -// This is not 100% accurate. As variant types comes -// as a simple slice with the types name in the first index -// and the value as the second. -// So there could be some edge cases where this structure is actual data -// and not a variant type although should be super rare. -func isVariant(v reflect.Value) bool { - if v.Kind() != reflect.Slice || v.Len() != 2 { - return false - } - - for v = v.Index(0); v.Kind() == reflect.Interface || v.Kind() == reflect.Pointer; v = v.Elem() { - // Intentionally empty - } - - return v.Kind() == reflect.String && isVariantName(v.String()) -} - -func parseTableDeltaData(v any) (map[string]interface{}, error) { - iface := parseTableDeltaDataInner(reflect.ValueOf(v)).Interface() - if out, ok := iface.(map[string]interface{}); ok { - return out, nil - } - return nil, fmt.Errorf("data is not an map") -} - -func parseTableDeltaDataInner(v reflect.Value) reflect.Value { - if isVariant(v) { - v = v.Index(1) - } - - switch v.Kind() { - case reflect.Interface: - return parseTableDeltaDataInner(v.Elem()) - case reflect.Slice: - for i := 0; i < v.Len(); i++ { - v.Index(i).Set(parseTableDeltaDataInner(v.Index(i))) - } - case reflect.Map: - it := v.MapRange() - for it.Next() { - v.SetMapIndex(it.Key(), parseTableDeltaDataInner(it.Value())) - } - } - - return v -} diff --git a/internal/server/ship_processor.go b/internal/server/ship_processor.go index 7106f4f..ad56305 100644 --- a/internal/server/ship_processor.go +++ b/internal/server/ship_processor.go @@ -6,6 +6,7 @@ import ( "github.com/eosswedenorg/thalos/api/message" "github.com/eosswedenorg/thalos/internal/abi" "github.com/eosswedenorg/thalos/internal/driver" + ship_helper "github.com/eosswedenorg/thalos/internal/ship" "github.com/eosswedenorg/thalos/internal/types" log "github.com/sirupsen/logrus" @@ -228,7 +229,7 @@ func (processor *ShipProcessor) proccessDeltaRows(logger *log.Entry, table_name v, err := processor.shipABI.Decode(bytes.NewReader(row.Data), table_name) if err == nil { - v, err := parseTableDeltaData(v) + v, err := ship_helper.ParseTableDeltaData(v) if err == nil { msg.Data = v } else { diff --git a/internal/ship/table_delta.go b/internal/ship/table_delta.go new file mode 100644 index 0000000..9d011d3 --- /dev/null +++ b/internal/ship/table_delta.go @@ -0,0 +1,36 @@ +package ship + +import ( + "fmt" + "reflect" +) + +func parseTableDeltaDataInner(v reflect.Value) reflect.Value { + if IsVariant(v) { + v = v.Index(1) + } + + switch v.Kind() { + case reflect.Interface: + return parseTableDeltaDataInner(v.Elem()) + case reflect.Slice: + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(parseTableDeltaDataInner(v.Index(i))) + } + case reflect.Map: + it := v.MapRange() + for it.Next() { + v.SetMapIndex(it.Key(), parseTableDeltaDataInner(it.Value())) + } + } + + return v +} + +func ParseTableDeltaData(v any) (map[string]interface{}, error) { + iface := parseTableDeltaDataInner(reflect.ValueOf(v)).Interface() + if out, ok := iface.(map[string]interface{}); ok { + return out, nil + } + return nil, fmt.Errorf("data is not an map") +} diff --git a/internal/server/helpers_test.go b/internal/ship/table_delta_test.go similarity index 93% rename from internal/server/helpers_test.go rename to internal/ship/table_delta_test.go index fdaf8ff..74b1d03 100644 --- a/internal/server/helpers_test.go +++ b/internal/ship/table_delta_test.go @@ -1,8 +1,9 @@ -package server +package ship_test import ( "testing" + "github.com/eosswedenorg/thalos/internal/ship" "github.com/stretchr/testify/assert" ) @@ -62,7 +63,7 @@ func TestParseTableDeltaData(t *testing.T) { "virtual_net_limit": 1048576000, } - actual, err := parseTableDeltaData(input) + actual, err := ship.ParseTableDeltaData(input) assert.NoError(t, err) assert.Equal(t, expected, actual) diff --git a/internal/ship/variant.go b/internal/ship/variant.go new file mode 100644 index 0000000..56ca7fb --- /dev/null +++ b/internal/ship/variant.go @@ -0,0 +1,93 @@ +package ship + +import "reflect" + +func IsVariantName(name string) bool { + validVariants := []string{ + "get_status_request_v0", + "block_position", + "get_status_result_v0", + "get_blocks_request_v0", + "get_blocks_ack_request_v0", + "get_blocks_result_v0", + "row", + "table_delta_v0", + "action", + "account_auth_sequence", + "action_receipt_v0", + "account_delta", + "action_trace_v0", + "partial_transaction_v0", + "transaction_trace_v0", + "packed_transaction", + "transaction_receipt_header", + "transaction_receipt", + "extension", + "block_header", + "signed_block_header", + "signed_block", + "transaction_header", + "transaction", + "code_id", + "account_v0", + "account_metadata_v0", + "code_v0", + "contract_table_v0", + "contract_row_v0", + "contract_index64_v0", + "contract_index128_v0", + "contract_index256_v0", + "contract_index_double_v0", + "contract_index_long_double_v0", + "producer_key", + "producer_schedule", + "block_signing_authority_v0", + "producer_authority", + "producer_authority_schedule", + "chain_config_v0", + "global_property_v0", + "global_property_v1", + "generated_transaction_v0", + "activated_protocol_feature_v0", + "protocol_state_v0", + "key_weight", + "permission_level", + "permission_level_weight", + "wait_weight", + "authority", + "permission_v0", + "permission_link_v0", + "resource_limits_v0", + "usage_accumulator_v0", + "resource_usage_v0", + "resource_limits_state_v0", + "resource_limits_ratio_v0", + "elastic_limit_parameters_v0", + "resource_limits_config_v0", + } + + for _, v := range validVariants { + if v == name { + return true + } + } + return false +} + +// Check if a structure is a variant type. +// This is not 100% accurate. As variant types comes +// as a simple slice with the types name in the first index +// and the value as the second. +// So there could be some edge cases where this structure is actual data +// and not a variant type although should be super rare. +func IsVariant(v reflect.Value) bool { + if v.Kind() != reflect.Slice || v.Len() != 2 { + return false + } + + for v = v.Index(0); v.Kind() == reflect.Interface || v.Kind() == reflect.Pointer; v = v.Elem() { + // Intentionally empty + } + + return v.Kind() == reflect.String && IsVariantName(v.String()) +}