Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified bin/console
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion exe/metadata
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ else
end

metadata = client.get_metadata(block_hash)
puts JSON.pretty_generate(metadata)
puts metadata.to_json
end
4 changes: 4 additions & 0 deletions lib/scale_rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ def debug(key, value)

require 'scale_rb/types'
require 'scale_rb/portable_registry'
require 'scale_rb/old_registry'
require 'scale_rb/codec'

require 'scale_rb/metadata/metadata'
require 'scale_rb/runtime_types'

require 'scale_rb/hasher'
require 'scale_rb/storage_helper'
Expand All @@ -34,3 +36,5 @@ def debug(key, value)
# clients
require 'scale_rb/client/http_client'
require 'scale_rb/client/ws_client'

require 'scale_rb/metadata/types_helper'
10 changes: 5 additions & 5 deletions lib/scale_rb/call_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module CallHelper
# "0x05000a1287977578f888bdc1c7627781af1cc000e6ab1300004c31b8d9a798"._to_bytes
def self.decode_call(callbytes, metadata)
pallet_index = callbytes[0]
pallet = Metadata.get_module_by_index(pallet_index, metadata)
pallet = metadata.pallet_by_index(pallet_index)

# Remove the pallet_index
# The callbytes we used below should not contain the pallet index.
Expand All @@ -20,7 +20,7 @@ def self.decode_call(callbytes, metadata)
decoded = Codec.decode(
calls_type_id,
callbytes_without_pallet_index,
Metadata.build_registry(metadata)
metadata.build_registry
)&.first

{
Expand All @@ -34,9 +34,9 @@ def self.decode_call(callbytes, metadata)
# {:pallet_name=>"Deposit", :call_name=>"claim", :call=>:claim]}
# {:pallet_name=>"Balances", :call_name=>"transfer", :call=>{:transfer=>{:dest=>[10, 18, 135, 151, 117, 120, 248, 136, 189, 193, 199, 98, 119, 129, 175, 28, 192, 0, 230, 171], :value=>11000000000000000000}}]}
def self.encode_call(call, metadata)
calls_type_id = Metadata.get_calls_type_id(call[:pallet_name], metadata)
pallet_index = Metadata.get_module(call[:pallet_name], metadata)._get(:index)
[pallet_index] + Codec.encode(calls_type_id, call[:call], Metadata.build_registry(metadata))
calls_type_id = metadata.calls_type_id(call[:pallet_name])
pallet_index = metadata.pallet(call[:pallet_name])[:index]
[pallet_index] + Codec.encode(calls_type_id, call[:call], metadata.build_registry)
end
end
end
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module ScaleRb
# This module is used to add extra methods to both the ScaleRb::WsClient ScaleRb::HttpClient
module ClientExt
module ClientShare
# get decoded metadata at block_hash
def get_metadata(block_hash = nil)
block_hash ||= chain_getHead
metadata_hex = state_getMetadata(block_hash)
Metadata.decode_metadata(metadata_hex)
Metadata::Metadata.from_hex(metadata_hex)
end

# Get decoded storage at block_hash
Expand Down Expand Up @@ -134,10 +134,8 @@ def get_storage1(block_hash, pallet_name, item_name, key, value, registry)
def get_storage2(block_hash, pallet_name, item_name, params, metadata)
raise 'Metadata should not be nil' if metadata.nil?

registry = Metadata.build_registry(metadata)
item = Metadata.get_storage_item(
pallet_name, item_name, metadata
)
registry = metadata.build_registry
item = metadata.storage(pallet_name, item_name)
raise "No such storage item: `#{pallet_name}`.`#{item_name}`" if item.nil?

modifier = item._get(:modifier) # Default | Optional
Expand Down
4 changes: 2 additions & 2 deletions lib/scale_rb/client/http_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
require 'net/http'
require 'json'

require_relative 'client_ext'
require_relative 'client_share'

module ScaleRb
class HttpClient
include ClientExt
include ClientShare
attr_accessor :supported_methods

def initialize(url)
Expand Down
4 changes: 2 additions & 2 deletions lib/scale_rb/client/ws_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require 'async/websocket/client'
require 'async/http/endpoint'

require_relative 'client_ext'
require_relative 'client_share'

module ScaleRb
class WsClient
Expand Down Expand Up @@ -52,7 +52,7 @@ def parse_message(message)

module ScaleRb
class WsClient
include ClientExt
include ClientShare
attr_accessor :supported_methods

def initialize(connection)
Expand Down
34 changes: 34 additions & 0 deletions lib/scale_rb/extrinsic_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module ScaleRb
module ExtrinsicHelper
def decode_extrinsic(bytes, metadata_prefixed)
meta = bytes[0]
signed = (meta & 0x80) == 0x80
version = (meta & 0x7f)

raise "Unsupported version: #{version}" unless version == 4

nil unless signed
end

def patch_types(registry, metadata_prefixed)
add_signed_extensions_type(metadata_prefixed.signed_extensions, registry)
end

private

def add_signed_extensions_type(signed_extensions, registry)
type = Types::StructType.new(
fields: signed_extensions.map do |signed_extension|
Types::Field.new(
name: Utils.camelize(signed_extension._get(:identifier)),
type: signed_extension._get(:type)
)
end,
registry:
)
registry.add_type(type)
end
end
end
140 changes: 73 additions & 67 deletions lib/scale_rb/metadata/metadata.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require_relative './registry'

require_relative './metadata_v9'
require_relative './metadata_v10'
require_relative './metadata_v11'
Expand All @@ -13,94 +11,102 @@
# https://github.com/paritytech/frame-metadata/blob/main/frame-metadata/src/lib.rs#L85
module ScaleRb
module Metadata
class << self
def decode_metadata(hex)
bytes = ScaleRb::Utils.hex_to_u8a(hex)

registry = ScaleRb::Metadata::Registry.new TYPES
metadata, = ScaleRb::Codec.decode('MetadataPrefixed', bytes, registry)
metadata
class Metadata
attr_reader :magic_number, :version, :metadata, :registry

def initialize(metadata_prefixed, types = nil)
@metadata_prefixed = metadata_prefixed
@magic_number = @metadata_prefixed[:magicNumber]
metadata = @metadata_prefixed[:metadata]
@version = metadata.keys.first
raise "Unsupported metadata version: #{@version}" unless [:V14, :V13, :V12, :V11, :V10, :V9].include?(@version)

@metadata = metadata[@version]
if @version == :V14
@registry = ScaleRb::PortableRegistry.new(@metadata.dig(:lookup, :types))
else
@registry = ScaleRb::OldRegistry.new(types)
end
end

def build_registry(metadata_prefixed)
types = ScaleRb::Utils.get(metadata_prefixed, :metadata, :V14, :lookup, :types)
ScaleRb::PortableRegistry.new(types)
def self.from_hex(hex)
metadata_prefixed, = ScaleRb::Codec.decode('MetadataPrefixed', Utils.hex_to_u8a(hex), OldRegistry.new(TYPES))
Metadata.new(metadata_prefixed)
end

def get_module(pallet_name, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first
raise NotImplementedError, version unless %i[V14].include?(version)

Metadata.const_get("Metadata#{version.upcase}").get_module(pallet_name, metadata_prefixed)
def self.from_json(str)
metadata_prefixed = JSON.parse(str, symbolize_names: true)
Metadata.new(metadata_prefixed)
end

def get_module_by_index(pallet_index, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first.to_sym
raise NotImplementedError, version unless %i[V14].include?(version)

Metadata.const_get("Metadata#{version.upcase}").get_module_by_index(pallet_index, metadata_prefixed)
def to_json(*_args)
JSON.pretty_generate(@metadata_prefixed)
end

def get_storage_item(pallet_name, item_name, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first.to_sym
raise NotImplementedError, version unless %i[V14].include?(version)
def pallet(pallet_name)
@metadata[:pallets].find do |pallet|
pallet[:name] == pallet_name
end
end

Metadata.const_get("Metadata#{version.upcase}").get_storage_item(pallet_name, item_name, metadata_prefixed)
def pallet_by_index(pallet_index)
@metadata[:pallets].find do |pallet|
pallet[:index] == pallet_index
end
end

def get_calls_type(pallet_name, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first.to_sym
raise NotImplementedError, version unless %i[V14].include?(version)
def storage(pallet_name, item_name)
pallet = pallet(pallet_name)
raise "Pallet `#{pallet_name}` not found" if pallet.nil?

Metadata.const_get("Metadata#{version.upcase}").get_calls_type(pallet_name, metadata_prefixed)
pallet.dig(:storage, :items).find do |item|
item[:name] == item_name
end
end

def get_calls_type_id(pallet_name, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first.to_sym
raise NotImplementedError, version unless %i[V14].include?(version)
def calls_type_id(pallet_name)
pallet = pallet(pallet_name)
raise "Pallet `#{pallet_name}` not found" if pallet.nil?

Metadata.const_get("Metadata#{version.upcase}").get_calls_type_id(pallet_name, metadata_prefixed)
pallet.dig(:calls, :type)
end

def get_call_type(pallet_name, call_name, metadata_prefixed)
metadata = Utils.get(metadata_prefixed, :metadata)
version = metadata.keys.first.to_sym
raise NotImplementedError, version unless %i[V14].include?(version)
def call(pallet_name, call_name)
calls_type_id = calls_type_id(pallet_name)
calls_type = @types[calls_type_id]
raise 'Calls type is not correct' if calls_type.nil?

Metadata.const_get("Metadata#{version.upcase}").get_call_type(pallet_name, call_name, metadata_prefixed)
calls_type.dig(:type, :def, :variant, :variants).find do |variant|
variant[:name].downcase == call_name.downcase
end
end
end

TYPES = {
Type: 'Str',
Bytes: 'Vec<u8>',
MetadataPrefixed: {
magicNumber: 'U32',
metadata: 'Metadata'
'Type' => 'Str',
'Bytes' => 'Vec<u8>',
'MetadataPrefixed' => {
'magicNumber' => 'U32',
'metadata' => 'Metadata'
},
Placeholder: 'Null',
Metadata: {
_enum: {
V0: 'Placeholder',
V1: 'Placeholder',
V2: 'Placeholder',
V3: 'Placeholder',
V4: 'Placeholder',
V5: 'Placeholder',
V6: 'Placeholder',
V7: 'Placeholder',
V8: 'Placeholder',
V9: 'MetadataV9',
V10: 'MetadataV10',
V11: 'MetadataV11',
V12: 'MetadataV12',
V13: 'MetadataV13',
V14: 'MetadataV14'
'Placeholder' => 'Null',
'Metadata' => {
'_enum' => {
'V0' => 'Placeholder',
'V1' => 'Placeholder',
'V2' => 'Placeholder',
'V3' => 'Placeholder',
'V4' => 'Placeholder',
'V5' => 'Placeholder',
'V6' => 'Placeholder',
'V7' => 'Placeholder',
'V8' => 'Placeholder',
'V9' => 'MetadataV9',
'V10' => 'MetadataV10',
'V11' => 'MetadataV11',
'V12' => 'MetadataV12',
'V13' => 'MetadataV13',
'V14' => 'MetadataV14'
}
}
}.merge(MetadataV14::TYPES)
Expand Down
Loading