Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add time provider #59

Merged
merged 1 commit into from
Aug 13, 2024
Merged
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
7 changes: 5 additions & 2 deletions Blockchain/Sources/Blockchain/Blockchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ public final class Blockchain: Sendable {
public let config: ProtocolConfigRef

private let dataProvider: BlockchainDataProvider
private let timeProvider: TimeProvider

public init(config: ProtocolConfigRef, dataProvider: BlockchainDataProvider) async {
public init(config: ProtocolConfigRef, dataProvider: BlockchainDataProvider, timeProvider: TimeProvider) async {
self.config = config
self.dataProvider = dataProvider
self.timeProvider = timeProvider
}

public func importBlock(_ block: BlockRef) async throws {
Expand All @@ -21,7 +23,8 @@ public final class Blockchain: Sendable {

let runtime = Runtime(config: config)
let parent = try await dataProvider.getState(hash: block.header.parentHash)
let state = try runtime.apply(block: block, state: parent)
let timeslot = timeProvider.getTime() / UInt32(config.value.slotPeriodSeconds)
let state = try runtime.apply(block: block, state: parent, context: .init(timeslot: timeslot))
try await dataProvider.add(state: state)
}
}
Expand Down
22 changes: 21 additions & 1 deletion Blockchain/Sources/Blockchain/Runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ public final class Runtime {
public enum Error: Swift.Error {
case safroleError(SafroleError)
case invalidValidatorEd25519Key
case invalidTimeslot
}

public struct ApplyContext {
public let timeslot: TimeslotIndex

public init(timeslot: TimeslotIndex) {
self.timeslot = timeslot
}
}

public let config: ProtocolConfigRef
Expand All @@ -13,7 +22,18 @@ public final class Runtime {
self.config = config
}

public func apply(block: BlockRef, state prevState: StateRef) throws(Error) -> StateRef {
public func validate(block: BlockRef, state _: StateRef, context: ApplyContext) throws(Error) {
guard context.timeslot >= block.header.timeslotIndex else {
throw Error.invalidTimeslot
}

// TODO: validate block.header.seal
// TODO: abstract input validation logic from Safrole state update function and call it here
}

public func apply(block: BlockRef, state prevState: StateRef, context: ApplyContext) throws(Error) -> StateRef {
try validate(block: block, state: prevState, context: context)

var newState = prevState.value
newState.lastBlock = block

Expand Down
35 changes: 35 additions & 0 deletions Blockchain/Sources/Blockchain/TimeProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Foundation

public protocol TimeProvider: Sendable {
func getTime() -> UInt32
}

public struct SystemTimeProvider: TimeProvider {
public init() {}

public func getTime() -> UInt32 {
Date().timeIntervalSinceJamCommonEra
}
}

public struct FixedTimeProvider: TimeProvider {
private let time: UInt32

public init(time: UInt32) {
self.time = time
}

public func getTime() -> UInt32 {
time
}
}

extension Date {
public var timeIntervalSinceJamCommonEra: UInt32 {
// the Jam Common Era: 1200 UTC on January 1, 2024
// number of seconds since the Unix epoch
let beginning = 1_704_110_400.0
let now = timeIntervalSince1970
return UInt32(now - beginning)
}
}
3 changes: 2 additions & 1 deletion Node/Sources/Node/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public class Node {

let genesisState = try genesis.toState(config: config.protcol)
let dataProvider = await InMemoryDataProvider(genesis: genesisState)
blockchain = await Blockchain(config: config.protcol, dataProvider: dataProvider)
let timeProvider = SystemTimeProvider()
blockchain = await Blockchain(config: config.protcol, dataProvider: dataProvider, timeProvider: timeProvider)

rpcServer = try Server(config: config.rpc, source: blockchain)
}
Expand Down