Skip to content

Commit

Permalink
fixed metadata parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ypopovych committed Jun 16, 2023
1 parent 2564901 commit 31b9575
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 53 deletions.
11 changes: 6 additions & 5 deletions Sources/Substrate/Config/DynamicRuntime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ public struct DynamicRuntime: Config {
}

public let extrinsicExtensions: [DynamicExtrinsicExtension]
public let headerName: String
public let headerTypeName: String

public init(extrinsicExtensions: [DynamicExtrinsicExtension] = Self.allExtensions,
headerName: String = "Header") {
headerTypeName: String = "sp_runtime.generic.header.Header") {
self.extrinsicExtensions = extrinsicExtensions
self.headerName = headerName
self.headerTypeName = headerTypeName
}

public func eventsStorageKey(runtime: any Runtime) throws -> any StorageKey<TBlockEvents> {
Expand All @@ -75,8 +75,9 @@ public struct DynamicRuntime: Config {
}

public func blockHeaderType(metadata: Metadata) throws -> RuntimeTypeInfo {
guard let type = metadata.resolve(type: headerName) else {
throw Error.headerTypeNotFound(headerName)
let path = headerTypeName.split(separator: ".").map { String($0) }
guard let type = metadata.resolve(type: path) else {
throw Error.headerTypeNotFound(headerTypeName)
}
return type
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/Substrate/Metadata/Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

public protocol RuntimeMetadata {
var version: UInt8 { get }
func asMetadata() -> Metadata
func asMetadata() throws -> Metadata

static var versions: Set<UInt32> { get }
}
Expand All @@ -22,7 +22,6 @@ public protocol Metadata {

func resolve(type id: RuntimeTypeId) -> RuntimeType?
func resolve(type path: [String]) -> RuntimeTypeInfo?
func resolve(type name: String) -> RuntimeTypeInfo?
func resolve(pallet index: UInt8) -> PalletMetadata?
func resolve(pallet name: String) -> PalletMetadata?
func resolve(api name: String) -> RuntimeApiMetadata?
Expand Down Expand Up @@ -78,3 +77,8 @@ public protocol RuntimeApiMetadata {

func resolve(method name: String) -> (params: [(String, RuntimeTypeInfo)], result: RuntimeTypeInfo)?
}

public enum MetadataError: Error {
case storageBadHashersCount(expected: Int, got: Int, name: String, pallet: String)
case storageNonCompositeKey(name: String, pallet: String, type: RuntimeTypeInfo)
}
89 changes: 58 additions & 31 deletions Sources/Substrate/Metadata/v14/MetadataV14.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,22 @@ public class MetadataV14: Metadata {
public var apis: [String] { [] }

public let types: [RuntimeTypeId: RuntimeType]
public let typesByName: [String: RuntimeTypeInfo]
public let typesByPath: [String: RuntimeTypeInfo] // joined by "."
public let palletsByIndex: [UInt8: PalletMetadataV14]
public let palletsByName: [String: PalletMetadataV14]

public init(runtime: RuntimeMetadataV14) {
public init(runtime: RuntimeMetadataV14) throws {
let types = Dictionary<RuntimeTypeId, RuntimeType>(
uniqueKeysWithValues: runtime.types.map { ($0.id, $0.type) }
)
self.runtime = runtime
self.types = types
self.typesByName = Dictionary(
uniqueKeysWithValues: runtime.types.map { ($0.type.path.last!, $0) }
)
self.typesByPath = Dictionary(
uniqueKeysWithValues: runtime.types.map { ($0.type.path.joined(separator: "."), $0) }
)
let byPathPairs = runtime.types.compactMap {
$0.type.path.count > 0 ? ($0.type.path.joined(separator: "."), $0) : nil
}
self.typesByPath = Dictionary(byPathPairs) { (l, r) in l }
self.extrinsic = ExtrinsicMetadataV14(runtime: runtime.extrinsic, types: types)
let pallets = runtime.pallets.map { PalletMetadataV14(runtime: $0, types: types) }
let pallets = try runtime.pallets.map { try PalletMetadataV14(runtime: $0, types: types) }
self.palletsByName = Dictionary(uniqueKeysWithValues: pallets.map { ($0.runtime.name, $0) })
self.palletsByIndex = Dictionary(uniqueKeysWithValues: pallets.map { ($0.runtime.index, $0) })
}
Expand All @@ -46,9 +43,6 @@ public class MetadataV14: Metadata {
typesByPath[path.joined(separator: ".")]
}

@inlinable
public func resolve(type name: String) -> RuntimeTypeInfo? { typesByName[name] }

@inlinable
public func resolve(pallet index: UInt8) -> PalletMetadata? { palletsByIndex[index] }

Expand All @@ -61,7 +55,6 @@ public class MetadataV14: Metadata {

public class PalletMetadataV14: PalletMetadata {
public let runtime: RuntimePalletMetadataV14
//public weak var metadata: MetadataV14?

@inlinable public var name: String { runtime.name }
@inlinable public var index: UInt8 { runtime.index }
Expand All @@ -84,9 +77,8 @@ public class PalletMetadataV14: PalletMetadata {
Array(constantByName.keys)
}

public init(runtime: RuntimePalletMetadataV14, types: [RuntimeTypeId: RuntimeType]) {
public init(runtime: RuntimePalletMetadataV14, types: [RuntimeTypeId: RuntimeType]) throws {
self.runtime = runtime
//self.metadata = metadata
self.call = runtime.call.map { RuntimeTypeInfo(id: $0, type: types[$0]!) }
self.event = runtime.event.map { RuntimeTypeInfo(id: $0, type: types[$0]!) }
let calls = self.call.flatMap { Self.variants(for: $0.type.definition) }
Expand All @@ -103,9 +95,12 @@ public class PalletMetadataV14: PalletMetadata {
self.eventNameByIdx = events.map {
Dictionary(uniqueKeysWithValues: $0.map { ($0.index, $0.name) })
}
self.storageByName = runtime.storage
.flatMap { $0.entries.map { ($0.name, StorageMetadataV14(runtime: $0, types: types)) } }
.flatMap { Dictionary(uniqueKeysWithValues: $0) }
self.storageByName = try runtime.storage
.flatMap {
try $0.entries.map {
try ($0.name, StorageMetadataV14(runtime: $0, pallet: runtime.name, types: types))
}
}.flatMap { Dictionary(uniqueKeysWithValues: $0) }
self.constantByName = Dictionary(
uniqueKeysWithValues: runtime.constants.map {
($0.name, ConstantMetadataV14(runtime: $0, types: types))
Expand Down Expand Up @@ -146,29 +141,61 @@ public class StorageMetadataV14: StorageMetadata {
public let defaultValue: Data
public let documentation: [String]

public init(runtime: RuntimePalletStorageEntryMedatadaV14, types: [RuntimeTypeId: RuntimeType]) {
public init(runtime: RuntimePalletStorageEntryMedatadaV14,
pallet: String,
types: [RuntimeTypeId: RuntimeType]
) throws {
self.name = runtime.name
self.modifier = runtime.modifier
self.defaultValue = runtime.defaultValue
self.documentation = runtime.documentation
var keys: [(StorageHasher, RuntimeTypeInfo)]
var valueType: RuntimeTypeId
switch runtime.type {
case .plain(let vType):
self.types = (keys: [], value: RuntimeTypeInfo(id: vType, type: types[vType]!))
keys = []
valueType = vType
case .map(hashers: let hashers, key: let kType, value: let vType):
var keys: [(StorageHasher, RuntimeTypeInfo)]
switch types[kType]!.definition {
case .composite(fields: let fields):
keys = zip(hashers, fields).map { hash, field in
(hash, RuntimeTypeInfo(id: field.type, type: types[field.type]!))
}
case .tuple(components: let fields):
keys = zip(hashers, fields).map { hash, field in
(hash, RuntimeTypeInfo(id: field, type: types[field]!))
valueType = vType
switch hashers.count {
case 0:
throw MetadataError.storageBadHashersCount(expected: 1,
got: 0,
name: runtime.name,
pallet: pallet)
case 1:
keys = [(hashers[0], RuntimeTypeInfo(id: kType, type: types[kType]!))]
default:
switch types[kType]!.definition {
case .tuple(components: let fields): // DoubleMap / NMap
guard hashers.count == fields.count else {
throw MetadataError.storageBadHashersCount(expected: fields.count,
got: hashers.count,
name: runtime.name,
pallet: pallet)
}
keys = zip(hashers, fields).map { hash, field in
(hash, RuntimeTypeInfo(id: field, type: types[field]!))
}
case .composite(fields: let fields): // Array / Struct
guard hashers.count == fields.count else {
throw MetadataError.storageBadHashersCount(expected: fields.count,
got: hashers.count,
name: runtime.name,
pallet: pallet)
}
keys = zip(hashers, fields).map { hash, field in
(hash, RuntimeTypeInfo(id: field.type, type: types[field.type]!))
}
default:
throw MetadataError.storageNonCompositeKey(
name: runtime.name, pallet: pallet,
type: RuntimeTypeInfo(id: kType, type: types[kType]!))
}
default: fatalError("Unknown storage key type: \(types[kType]!)")
}
self.types = (keys: keys, value: RuntimeTypeInfo(id: vType, type: types[vType]!))
}
self.types = (keys: keys,
value: RuntimeTypeInfo(id: valueType, type: types[valueType]!))
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/Substrate/Metadata/v14/RuntimeMetadataV14.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ public class RuntimeMetadataV14: ScaleCodable, RuntimeMetadata {
.encode(extrinsic).encode(runtimeType)
}

public func asMetadata() -> Metadata {
MetadataV14(runtime: self)
public func asMetadata() throws -> Metadata {
try MetadataV14(runtime: self)
}

public class var versions: Set<UInt32> { [14] }
Expand Down
4 changes: 2 additions & 2 deletions Sources/Substrate/Metadata/v15/MetadataV15.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class MetadataV15: MetadataV14 {
public private(set) var apisByName: [String: RuntimeApiMetadataV15]!
public override var apis: [String] { Array(apisByName.keys) }

public init(runtime: RuntimeMetadataV15) {
super.init(runtime: runtime)
public init(runtime: RuntimeMetadataV15) throws {
try super.init(runtime: runtime)
self.apisByName = Dictionary(
uniqueKeysWithValues: runtime.apis.map {
($0.name, RuntimeApiMetadataV15(runtime: $0, types: types))
Expand Down
4 changes: 2 additions & 2 deletions Sources/Substrate/Metadata/v15/RuntimeMetadataV15.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class RuntimeMetadataV15: RuntimeMetadataV14 {
try encoder.encode(apis)
}

public override func asMetadata() -> Metadata {
MetadataV15(runtime: self)
public override func asMetadata() throws -> Metadata {
try MetadataV15(runtime: self)
}

public override class var versions: Set<UInt32> { [15, UInt32.max] }
Expand Down
6 changes: 0 additions & 6 deletions Sources/Substrate/Runtime/Runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public protocol Runtime: AnyObject {
func decoder(with data: Data) -> any ScaleDecoder

func resolve(type id: RuntimeTypeId) -> RuntimeType?
func resolve(type named: String) -> RuntimeTypeInfo?
func resolve(type path: [String]) -> RuntimeTypeInfo?
func resolve(palletName index: UInt8) -> String?
func resolve(palletIndex name: String) -> UInt8?
Expand Down Expand Up @@ -68,11 +67,6 @@ public extension Runtime {
metadata.resolve(type: id)
}

@inlinable
func resolve(type named: String) -> RuntimeTypeInfo? {
metadata.resolve(type: named)
}

@inlinable
func resolve(type path: [String]) -> RuntimeTypeInfo? {
metadata.resolve(type: path)
Expand Down
6 changes: 3 additions & 3 deletions Sources/Substrate/Types/Hashers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ public struct AnyFixedHasher: FixedHasher {

public init?(name: String) {
switch name.lowercased() {
case "blake2b128": self = .blake2b128
case "blake2b256": self = .blake2b256
case "blake2b512": self = .blake2b512
case "blake2b128", "blaketwo128": self = .blake2b128
case "blake2b256", "blaketwo256": self = .blake2b256
case "blake2b512", "blaketwo512": self = .blake2b512
case "xx128", "twox128": self = .xx128
case "xx256", "twox256": self = .xx256
default: return nil
Expand Down

0 comments on commit 31b9575

Please sign in to comment.