Skip to content

Commit

Permalink
Merge branch 'master' into dev_mackun
Browse files Browse the repository at this point in the history
* master:
  update ignore
  Encoded size (#95)
  • Loading branch information
MacOMNI committed Aug 31, 2024
2 parents bbca81e + e05af5c commit 29dfba6
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Codec
import Utils

public struct AvailabilitySpecifications: Sendable, Equatable, Codable {
Expand Down Expand Up @@ -37,3 +38,13 @@ extension AvailabilitySpecifications: Dummy {
)
}
}

extension AvailabilitySpecifications: EncodedSize {
public var encodedSize: Int {
workPackageHash.encodedSize + length.encodedSize + erasureRoot.encodedSize + segmentRoot.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}
31 changes: 31 additions & 0 deletions Blockchain/Sources/Blockchain/Types/RefinementContext.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Codec
import Utils

// A refinement context, denoted by the set X, describes the context of the chain
Expand Down Expand Up @@ -68,3 +69,33 @@ extension RefinementContext: Dummy {
)
}
}

extension RefinementContext.Anchor: EncodedSize {
public var encodedSize: Int {
headerHash.encodedSize + stateRoot.encodedSize + beefyRoot.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension RefinementContext.LokupAnchor: EncodedSize {
public var encodedSize: Int {
headerHash.encodedSize + timeslot.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension RefinementContext: EncodedSize {
public var encodedSize: Int {
anchor.encodedSize + lokupAnchor.encodedSize + prerequistieWorkPackage.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}
8 changes: 3 additions & 5 deletions Blockchain/Sources/Blockchain/Types/State+Merklization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ extension State {
}

private static func constructKey(_ service: ServiceIndex, _ codeHash: Data32) -> Data32 {
var data = Data()
data.reserveCapacity(32)
var data = Data(capacity: 32)
withUnsafeBytes(of: service) { ptr in
data.append(ptr.load(as: UInt8.self))
data.append(codeHash.data[0])
Expand Down Expand Up @@ -81,10 +80,9 @@ extension State {
}

private func encode(_ account: ServiceAccount) throws -> Data {
var data = Data()
data.reserveCapacity(32 + 8 * 4 + 4) // codeHash, balance, accumlateGasLimit, onTransferGasLimit, totalByteLength, itemsCount
let capacity = 32 + 8 * 4 + 4 // codeHash, balance, accumlateGasLimit, onTransferGasLimit, totalByteLength, itemsCount

let encoder = JamEncoder(data)
let encoder = JamEncoder(capacity: capacity)

try encoder.encode(account.codeHash)
try encoder.encode(account.balance)
Expand Down
15 changes: 15 additions & 0 deletions Blockchain/Sources/Blockchain/Types/WorkOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,18 @@ extension WorkOutput: Codable {
}
}
}

extension WorkOutput: EncodedSize {
public var encodedSize: Int {
switch result {
case let .success(success):
success.encodedSize + 1
case .failure:
1
}
}

public static var encodeedSizeHint: Int? {
nil
}
}
11 changes: 11 additions & 0 deletions Blockchain/Sources/Blockchain/Types/WorkReport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,14 @@ extension WorkReport {
try! JamEncoder.encode(self).blake2b256hash()
}
}

extension WorkReport: EncodedSize {
public var encodedSize: Int {
authorizerHash.encodedSize + coreIndex.encodedSize + output.encodedSize + refinementContext.encodedSize + packageSpecification
.encodedSize + results.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}
10 changes: 10 additions & 0 deletions Blockchain/Sources/Blockchain/Types/WorkResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,13 @@ extension WorkResult: Dummy {
)
}
}

extension WorkResult: EncodedSize {
public var encodedSize: Int {
serviceIndex.encodedSize + codeHash.encodedSize + payloadHash.encodedSize + gas.encodedSize + output.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}
111 changes: 111 additions & 0 deletions Codec/Sources/Codec/EncodedSize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import Foundation

public protocol EncodedSize {
var encodedSize: Int { get }

static var encodeedSizeHint: Int? { get }
}

extension FixedWidthInteger {
public var encodedSize: Int {
MemoryLayout<Self>.size
}

public static var encodeedSizeHint: Int? {
MemoryLayout<Self>.size
}
}

extension Bool: EncodedSize {
public var encodedSize: Int {
1
}

public static var encodeedSizeHint: Int? {
1
}
}

extension String: EncodedSize {
public var encodedSize: Int {
utf8.count
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Data: EncodedSize {
public var encodedSize: Int {
UInt32(count).variableEncodingLength() + count
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Array: EncodedSize where Element: EncodedSize {
public var encodedSize: Int {
let prefixSize = UInt32(count).variableEncodingLength()
if let hint = Element.encodeedSizeHint {
return prefixSize + hint * count
}
return reduce(into: prefixSize) { $0 += $1.encodedSize }
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Optional: EncodedSize where Wrapped: EncodedSize {
public var encodedSize: Int {
switch self {
case let .some(wrapped):
wrapped.encodedSize + 1
case .none:
1
}
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Result: EncodedSize where Success: EncodedSize, Failure: EncodedSize {
public var encodedSize: Int {
switch self {
case let .success(success):
success.encodedSize + 1
case let .failure(failure):
failure.encodedSize + 1
}
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Set: EncodedSize where Element: EncodedSize {
public var encodedSize: Int {
reduce(into: UInt32(count).variableEncodingLength()) { $0 += $1.encodedSize }
}

public static var encodeedSizeHint: Int? {
nil
}
}

extension Dictionary: EncodedSize where Key: EncodedSize, Value: EncodedSize {
public var encodedSize: Int {
reduce(into: UInt32(count).variableEncodingLength()) { $0 += $1.key.encodedSize + $1.value.encodedSize }
}

public static var encodeedSizeHint: Int? {
nil
}
}
16 changes: 9 additions & 7 deletions Codec/Sources/Codec/JamEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@ public class JamEncoder {
encoder = EncodeContext(data)
}

public init(capacity: Int) {
encoder = EncodeContext(Data(capacity: capacity))
}

public func encode(_ value: some Encodable) throws {
try encoder.encode(value)
}

public static func encode(_ value: some Encodable) throws -> Data {
let encoder = JamEncoder()
let encoder = if let value = value as? EncodedSize {
JamEncoder(capacity: value.encodedSize)
} else {
JamEncoder()
}
try encoder.encode(value)
return encoder.data
}
Expand Down Expand Up @@ -55,9 +63,6 @@ private class EncodeContext: Encoder {
}

fileprivate func encodeData(_ value: Data, lengthPrefix: Bool) {
// reserve capacity for the length
// length is variable size but very unlikely to be larger than 4 bytes
data.reserveCapacity(data.count + value.count + (lengthPrefix ? 4 : 0))
if lengthPrefix {
let length = UInt32(value.count)
data.append(contentsOf: length.encode(method: .variableWidth))
Expand All @@ -66,9 +71,6 @@ private class EncodeContext: Encoder {
}

fileprivate func encodeData(_ value: [UInt8]) {
// reserve capacity for the length
// length is variable size but very unlikely to be larger than 4 bytes
data.reserveCapacity(data.count + value.count + 4)
let length = UInt32(value.count)
data.append(contentsOf: length.encode(method: .variableWidth))
data.append(contentsOf: value)
Expand Down
10 changes: 8 additions & 2 deletions Codec/Sources/Codec/UnsignedInteger+Codec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,18 @@ extension UnsignedInteger {
}

public func encode() -> Data {
var data = Data()
data.reserveCapacity(MemoryLayout<Self>.size)
var data = Data(capacity: MemoryLayout<Self>.size)
// use withUnsafeBytes to avoid the overhead of creating a copy of the data
withUnsafeBytes(of: self) { bytes in
data.append(contentsOf: bytes)
}
return data
}

public func variableEncodingLength() -> Int {
for l in 1 ..< 9 where self < (1 << (7 * l)) {
return l
}
return 9
}
}
17 changes: 17 additions & 0 deletions Utils/Sources/Utils/ConfigLimitedSizeArray.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Codec

// TODO: add tests
// TODO: consider using a circular buffer instead of a regular array to reduce memory usage

Expand Down Expand Up @@ -235,3 +237,18 @@ extension ConfigLimitedSizeArray: Encodable where T: Encodable {
}
}
}

extension ConfigLimitedSizeArray: EncodedSize where T: EncodedSize {
public var encodedSize: Int {
if TMinLength.self == TMaxLength.self {
if let hint = T.encodeedSizeHint {
return count * hint
}
}
return array.encodedSize
}

public static var encodeedSizeHint: Int? {
nil
}
}
10 changes: 10 additions & 0 deletions Utils/Sources/Utils/ConfigSizeBitString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,13 @@ extension ConfigSizeBitString: FixedLengthData {
try self.init(config: config, data: data)
}
}

extension ConfigSizeBitString: EncodedSize {
public var encodedSize: Int {
UInt32(length).variableEncodingLength() + bytes.count
}

public static var encodeedSizeHint: Int? {
nil
}
}
20 changes: 20 additions & 0 deletions Utils/Sources/Utils/Either.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Codec

public enum Either<Left, Right> {
case left(Left)
case right(Right)
Expand Down Expand Up @@ -84,3 +86,21 @@ extension Either: Codable where Left: Codable, Right: Codable {
}
}
}

extension Either: EncodedSize where Left: EncodedSize, Right: EncodedSize {
public var encodedSize: Int {
switch self {
case let .left(left):
left.encodedSize + 1
case let .right(right):
right.encodedSize + 1
}
}

public static var encodeedSizeHint: Int? {
if let left = Left.encodeedSizeHint, let right = Right.encodeedSizeHint {
return left + right + 1
}
return nil
}
}
10 changes: 10 additions & 0 deletions Utils/Sources/Utils/FixedSizeData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ extension FixedSizeData: FixedLengthData {
}
}

extension FixedSizeData: EncodedSize {
public var encodedSize: Int {
T.value
}

public static var encodeedSizeHint: Int? {
T.value
}
}

public typealias Data32 = FixedSizeData<ConstInt32>
public typealias Data48 = FixedSizeData<ConstInt48>
public typealias Data64 = FixedSizeData<ConstInt64>
Expand Down
Loading

0 comments on commit 29dfba6

Please sign in to comment.