Skip to content
This repository has been archived by the owner on Oct 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #77 from horizontalsystems/peer_group_refactoring
Browse files Browse the repository at this point in the history
Peer group refactoring
  • Loading branch information
esen committed Mar 22, 2019
2 parents 4f15a5c + e8189a7 commit dc16f81
Show file tree
Hide file tree
Showing 20 changed files with 793 additions and 136 deletions.
26 changes: 26 additions & 0 deletions HSEthereumKit/HSEthereumKit.xcodeproj/project.pbxproj
Expand Up @@ -13,15 +13,21 @@
11B35169E195D2801E57AD81 /* FrameConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B353E4C00F4D12A5401C6F /* FrameConnection.swift */; };
11B3518C1848401DE249961E /* ApiBlockchain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35AC255BE64FE27CB8220 /* ApiBlockchain.swift */; };
11B353DA20E3DD02F8C8D4D4 /* LESPeerRequestHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35434455A2AF945B2BD1B /* LESPeerRequestHolder.swift */; };
11B35405B7E0C4928E078F76 /* PeerGroupState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3563AB847E272EE94FECD /* PeerGroupState.swift */; };
11B354A47ED18CDC0599ED49 /* PeerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35C30343C696F41F7EC66 /* PeerProvider.swift */; };
11B356030FB7878C2BD0C5A8 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B357626B809CC6A964D5B1 /* Logger.swift */; };
11B3563CCAB1B50D85984C7E /* CapabilityHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351D958CC3C4A60EEEC9D /* CapabilityHelperTests.swift */; };
11B356BF054DFC99D8EB19E5 /* GeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359F34D40C2E21B4CD620 /* GeneratedMocks.swift */; };
11B358F1C8520185D515F5C8 /* BlockchainState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B355F58513F030F5E8E201 /* BlockchainState.swift */; };
11B3592A8ADE33386B8D5783 /* MaxCost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35CF0B3192008B47AAACB /* MaxCost.swift */; };
11B359FF9CFC6CEFEECFBEAC /* BlockValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3559A823FD2E479FB53EB /* BlockValidatorTests.swift */; };
11B35A0D90F7DDB2DE3D2FEC /* BlockHeaderRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359DA0DDE45734AB73E25 /* BlockHeaderRequest.swift */; };
11B35A4116607D8C5B444E37 /* EthereumKitState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B3567B8F9696AA05DFFADE /* EthereumKitState.swift */; };
11B35AA6B3D4826B649A4985 /* BlockValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B358B81C30D5D2AAD8B85C /* BlockValidator.swift */; };
11B35B0D2D815D5A08BE4C54 /* BlockHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B356EE4167A9EF2D429826 /* BlockHelper.swift */; };
11B35C62ACE0870699401F3F /* CapabilityHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35074A6F5AB51D13B06BE /* CapabilityHelper.swift */; };
11B35CEF617BCF783C3D1DCA /* EthereumTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B359B70EC74CF5E6CFBC0C /* EthereumTransaction.swift */; };
11B35D680CDB83B30D29187F /* PeerGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B351260B945ADB1196EA18 /* PeerGroupTests.swift */; };
11B35EAEAEC58D077071352A /* LESPeerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35FFC4D818569376084A3 /* LESPeerTests.swift */; };
11B35EB873DF5DDFC6B5207C /* DevP2PPeerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35A34A00570C3752F1EBC /* DevP2PPeerTests.swift */; };
11B35F9251133330AD1C5F38 /* ApiGrdbStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35E9EFA334E9433C71CD4 /* ApiGrdbStorage.swift */; };
Expand Down Expand Up @@ -154,18 +160,24 @@
/* Begin PBXFileReference section */
11B35074A6F5AB51D13B06BE /* CapabilityHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapabilityHelper.swift; sourceTree = "<group>"; };
11B350977535A5956D227887 /* EthereumKitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EthereumKitTests.swift; sourceTree = "<group>"; };
11B351260B945ADB1196EA18 /* PeerGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerGroupTests.swift; sourceTree = "<group>"; };
11B351D958CC3C4A60EEEC9D /* CapabilityHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapabilityHelperTests.swift; sourceTree = "<group>"; };
11B353E4C00F4D12A5401C6F /* FrameConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrameConnection.swift; sourceTree = "<group>"; };
11B35434455A2AF945B2BD1B /* LESPeerRequestHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LESPeerRequestHolder.swift; sourceTree = "<group>"; };
11B3554DD0D3D4A6F7D9005C /* EthereumBalance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EthereumBalance.swift; sourceTree = "<group>"; };
11B3559A823FD2E479FB53EB /* BlockValidatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockValidatorTests.swift; sourceTree = "<group>"; };
11B355F58513F030F5E8E201 /* BlockchainState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainState.swift; sourceTree = "<group>"; };
11B3563AB847E272EE94FECD /* PeerGroupState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerGroupState.swift; sourceTree = "<group>"; };
11B3567B8F9696AA05DFFADE /* EthereumKitState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EthereumKitState.swift; sourceTree = "<group>"; };
11B356EE4167A9EF2D429826 /* BlockHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockHelper.swift; sourceTree = "<group>"; };
11B357626B809CC6A964D5B1 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
11B358B81C30D5D2AAD8B85C /* BlockValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockValidator.swift; sourceTree = "<group>"; };
11B359B70EC74CF5E6CFBC0C /* EthereumTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EthereumTransaction.swift; sourceTree = "<group>"; };
11B359DA0DDE45734AB73E25 /* BlockHeaderRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockHeaderRequest.swift; sourceTree = "<group>"; };
11B359F34D40C2E21B4CD620 /* GeneratedMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedMocks.swift; sourceTree = "<group>"; };
11B35A34A00570C3752F1EBC /* DevP2PPeerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DevP2PPeerTests.swift; sourceTree = "<group>"; };
11B35AC255BE64FE27CB8220 /* ApiBlockchain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiBlockchain.swift; sourceTree = "<group>"; };
11B35C30343C696F41F7EC66 /* PeerProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerProvider.swift; sourceTree = "<group>"; };
11B35CC13BE2809A1D47FC37 /* DevP2PConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DevP2PConnection.swift; sourceTree = "<group>"; };
11B35CF0B3192008B47AAACB /* MaxCost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaxCost.swift; sourceTree = "<group>"; };
11B35E9EFA334E9433C71CD4 /* ApiGrdbStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiGrdbStorage.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -602,6 +614,8 @@
D045FC20221C19F20009BEF6 /* Connection */,
11B35F4F299FD99CFF8E479E /* DevP2P */,
11B35F50E72AC9C4CF5AFADD /* LES */,
11B351260B945ADB1196EA18 /* PeerGroupTests.swift */,
11B3559A823FD2E479FB53EB /* BlockValidatorTests.swift */,
);
path = Net;
sourceTree = "<group>";
Expand Down Expand Up @@ -680,6 +694,10 @@
2FA5DC4BD52779213E1952A6 /* PeerGroup.swift */,
2FA5D05F4E0D54E432282958 /* Ropsten.swift */,
2FA5D51BD89CC6356F1E6138 /* Node.swift */,
11B35C30343C696F41F7EC66 /* PeerProvider.swift */,
11B3563AB847E272EE94FECD /* PeerGroupState.swift */,
11B358B81C30D5D2AAD8B85C /* BlockValidator.swift */,
11B356EE4167A9EF2D429826 /* BlockHelper.swift */,
);
path = Net;
sourceTree = "<group>";
Expand Down Expand Up @@ -910,6 +928,8 @@
"$(SRCROOT)/HSEthereumKit/Spv/Core/SpvProtocols.swift",
"$(SRCROOT)/HSEthereumKit/Spv/Net/LES/LESPeerRequestHolder.swift",
"$(SRCROOT)/HSEthereumKit/Spv/Net/LES/Requests/AccountStateRequest.swift",
"$(SRCROOT)/HSEthereumKit/Spv/Net/PeerGroupState.swift",
"$(SRCROOT)/HSEthereumKit/Spv/Net/BlockValidator.swift",
);
name = Cuckoo;
outputPaths = (
Expand Down Expand Up @@ -1008,6 +1028,8 @@
11B35EB873DF5DDFC6B5207C /* DevP2PPeerTests.swift in Sources */,
11B35EAEAEC58D077071352A /* LESPeerTests.swift in Sources */,
11B3563CCAB1B50D85984C7E /* CapabilityHelperTests.swift in Sources */,
11B35D680CDB83B30D29187F /* PeerGroupTests.swift in Sources */,
11B359FF9CFC6CEFEECFBEAC /* BlockValidatorTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1130,6 +1152,10 @@
11B3592A8ADE33386B8D5783 /* MaxCost.swift in Sources */,
1A564FD1E7912DE963C79EB8 /* GasPrice.swift in Sources */,
1A564C0DCC46C4B225F37BDA /* IPFS.swift in Sources */,
11B354A47ED18CDC0599ED49 /* PeerProvider.swift in Sources */,
11B35405B7E0C4928E078F76 /* PeerGroupState.swift in Sources */,
11B35AA6B3D4826B649A4985 /* BlockValidator.swift in Sources */,
11B35B0D2D815D5A08BE4C54 /* BlockHelper.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
16 changes: 12 additions & 4 deletions HSEthereumKit/HSEthereumKit/Spv/Core/SpvBlockchain.swift
Expand Up @@ -33,7 +33,7 @@ extension SpvBlockchain: IBlockchain {
}

var syncState: EthereumKit.SyncState {
return EthereumKit.SyncState.synced
return peerGroup.syncState
}

func syncState(contractAddress: String) -> EthereumKit.SyncState {
Expand All @@ -59,8 +59,12 @@ extension SpvBlockchain: IBlockchain {

extension SpvBlockchain: IPeerGroupDelegate {

func onUpdate(state: AccountState) {
delegate?.onUpdate(balance: state.balance.wei.asString(withBase: 10))
func onUpdate(syncState: EthereumKit.SyncState) {
delegate?.onUpdate(syncState: syncState)
}

func onUpdate(accountState: AccountState) {
delegate?.onUpdate(balance: accountState.balance.wei.asString(withBase: 10))
}

}
Expand All @@ -84,7 +88,11 @@ extension SpvBlockchain {
publicKeyPoint: ECPoint(nodeId: connectionPublicKey)
)

let peerGroup = PeerGroup(network: Ropsten(), storage: storage, connectionKey: connectionECKey, address: addressData, logger: logger)
let peerProvider = PeerProvider(network: network, storage: storage, connectionKey: connectionECKey, logger: logger)
let validator = BlockValidator()
let blockHelper = BlockHelper(storage: storage, network: network)

let peerGroup = PeerGroup(storage: storage, peerProvider: peerProvider, validator: validator, blockHelper: blockHelper, address: addressData, logger: logger)

let spvBlockchain = SpvBlockchain(peerGroup: peerGroup, ethereumAddress: address)

Expand Down
18 changes: 15 additions & 3 deletions HSEthereumKit/HSEthereumKit/Spv/Core/SpvGrdbStorage.swift
Expand Up @@ -55,15 +55,15 @@ class SpvGrdbStorage {
t.column(BlockHeader.Columns.receiptsRoot.name, .blob).notNull()
t.column(BlockHeader.Columns.logsBloom.name, .blob).notNull()
t.column(BlockHeader.Columns.difficulty.name, .text).notNull()
t.column(BlockHeader.Columns.height.name, .text).notNull()
t.column(BlockHeader.Columns.height.name, .integer).notNull()
t.column(BlockHeader.Columns.gasLimit.name, .integer).notNull()
t.column(BlockHeader.Columns.gasUsed.name, .integer).notNull()
t.column(BlockHeader.Columns.timestamp.name, .integer).notNull()
t.column(BlockHeader.Columns.extraData.name, .blob).notNull()
t.column(BlockHeader.Columns.mixHash.name, .blob).notNull()
t.column(BlockHeader.Columns.nonce.name, .blob).notNull()

t.primaryKey([BlockHeader.Columns.hashHex.name], onConflict: .replace)
t.primaryKey([BlockHeader.Columns.height.name], onConflict: .replace)
}
}

Expand All @@ -75,7 +75,7 @@ class SpvGrdbStorage {
extension SpvGrdbStorage: ISpvStorage {

var lastBlockHeight: Int? {
return lastBlockHeader?.height.toInt()
return lastBlockHeader?.height
}

func balance(forAddress address: String) -> String? {
Expand Down Expand Up @@ -122,6 +122,18 @@ extension SpvGrdbStorage: ISpvStorage {
}
}

func blockHeader(height: Int) -> BlockHeader? {
return try! dbPool.read { db in
try BlockHeader.filter(BlockHeader.Columns.height == height).fetchOne(db)
}
}

func reversedLastBlockHeaders(from height: Int, limit: Int) -> [BlockHeader] {
return try! dbPool.read { db in
try BlockHeader.filter(BlockHeader.Columns.height <= height).order(Column("height").desc).limit(limit).fetchAll(db)
}
}

func save(blockHeaders: [BlockHeader]) {
_ = try? dbPool.write { db in
for header in blockHeaders {
Expand Down
29 changes: 22 additions & 7 deletions HSEthereumKit/HSEthereumKit/Spv/Core/SpvProtocols.swift
Expand Up @@ -3,6 +3,8 @@ import HSCryptoKit

protocol ISpvStorage: IStorage {
var lastBlockHeader: BlockHeader? { get }
func blockHeader(height: Int) -> BlockHeader?
func reversedLastBlockHeaders(from height: Int, limit: Int) -> [BlockHeader]
func save(blockHeaders: [BlockHeader])
}

Expand Down Expand Up @@ -57,12 +59,13 @@ public protocol IEthereumKitDelegate: class {
}


protocol ILESPeerDelegate: class {
protocol IPeerDelegate: class {
func didConnect()
func didDisconnect(error: Error?)

func didReceive(blockHeaders: [BlockHeader], blockHash: Data)
func didReceive(blockHeaders: [BlockHeader], blockHeader: BlockHeader, reverse: Bool)
func didReceive(accountState: AccountState, address: Data, blockHeader: BlockHeader)
func didAnnounce(blockHash: Data, blockHeight: BInt)
func didAnnounce(blockHash: Data, blockHeight: Int)
}

protocol IDevP2PPeerDelegate: class {
Expand All @@ -77,13 +80,13 @@ protocol IConnectionDelegate: class {
func didReceive(frame: Frame)
}

protocol ILESPeer: class {
var delegate: ILESPeerDelegate? { get set }
protocol IPeer: class {
var delegate: IPeerDelegate? { get set }

func connect()
func disconnect(error: Error?)

func requestBlockHeaders(blockHash: Data, limit: Int)
func requestBlockHeaders(blockHeader: BlockHeader, limit: Int, reverse: Bool)
func requestAccountState(address: Data, blockHeader: BlockHeader)
}

Expand Down Expand Up @@ -135,11 +138,15 @@ protocol INetwork {
}

protocol IPeerGroupDelegate: class {
func onUpdate(state: AccountState)
func onUpdate(syncState: EthereumKit.SyncState)
func onUpdate(accountState: AccountState)
}

protocol IPeerGroup {
var delegate: IPeerGroupDelegate? { get set }

var syncState: EthereumKit.SyncState { get }

func start()
}

Expand All @@ -164,3 +171,11 @@ protocol IOutMessage: IMessage {
protocol ICapabilityHelper {
func sharedCapabilities(myCapabilities: [Capability], nodeCapabilities: [Capability]) -> [Capability]
}

protocol IPeerProvider {
func peer() -> IPeer
}

protocol IBlockHelper {
var lastBlockHeader: BlockHeader { get }
}
10 changes: 5 additions & 5 deletions HSEthereumKit/HSEthereumKit/Spv/Models/BlockHeader.swift
Expand Up @@ -4,10 +4,10 @@ class BlockHeader: Record {

static let EMPTY_TRIE_HASH = CryptoUtils.shared.sha3(RLP.encode([]))

let hashHex: Data
var hashHex: Data
var totalDifficulty: BInt = 0 // Scalar value corresponding to the sum of difficulty values of all previous blocks

let parentHash: Data // 256-bit Keccak-256 hash of parent block
var parentHash: Data // 256-bit Keccak-256 hash of parent block
let unclesHash: Data // 256-bit Keccak-256 hash of uncles portion of this block
let coinbase: Data // 160-bit address for fees collected from successful mining
let stateRoot: Data // 256-bit state trie root hash
Expand All @@ -19,7 +19,7 @@ class BlockHeader: Record {
let difficulty: BInt /* A scalar value corresponding to the difficulty level of this block.
* This can be calculated from the previous block’s difficulty level
* and the timestamp */
let height: BInt
var height: Int
let gasLimit: Int // A scalar value equal to the current limit of gas expenditure per block
let gasUsed: Int // A scalar value equal to the total gas used in transactions in this block
let timestamp: Int // A scalar value equal to the reasonable output of Unix's time() at this block's inception
Expand All @@ -32,7 +32,7 @@ class BlockHeader: Record {

init(hashHex: Data, totalDifficulty: BInt, parentHash: Data, unclesHash: Data, coinbase: Data,
stateRoot: Data, transactionsRoot: Data, receiptsRoot: Data, logsBloom: Data,
difficulty: BInt, height: BInt, gasLimit: Int, gasUsed: Int, timestamp: Int,
difficulty: BInt, height: Int, gasLimit: Int, gasUsed: Int, timestamp: Int,
extraData: Data, mixHash: Data, nonce: Data) {
self.hashHex = hashHex
self.totalDifficulty = totalDifficulty
Expand Down Expand Up @@ -79,7 +79,7 @@ class BlockHeader: Record {

self.logsBloom = rlpList[6].dataValue
self.difficulty = try rlpList[7].bIntValue()
self.height = try rlpList[8].bIntValue()
self.height = try rlpList[8].intValue()
self.gasLimit = try rlpList[9].intValue()
self.gasUsed = try rlpList[10].intValue()
self.timestamp = try rlpList[11].intValue()
Expand Down
18 changes: 18 additions & 0 deletions HSEthereumKit/HSEthereumKit/Spv/Net/BlockHelper.swift
@@ -0,0 +1,18 @@
class BlockHelper {
private let storage: ISpvStorage
private let network: INetwork

init(storage: ISpvStorage, network: INetwork) {
self.storage = storage
self.network = network
}

}

extension BlockHelper: IBlockHelper {

var lastBlockHeader: BlockHeader {
return storage.lastBlockHeader ?? network.checkpointBlock
}

}
32 changes: 32 additions & 0 deletions HSEthereumKit/HSEthereumKit/Spv/Net/BlockValidator.swift
@@ -0,0 +1,32 @@
class BlockValidator {

func validate(blockHeaders: [BlockHeader], from blockHeader: BlockHeader) throws {
guard let firstBlockHeader = blockHeaders.first else {
throw ValidationError.invalidChain
}

guard firstBlockHeader.hashHex == blockHeader.hashHex else {
throw ValidationError.forkDetected
}

var previousHeader = blockHeader

for blockHeader in blockHeaders.dropFirst() {
guard blockHeader.parentHash == previousHeader.hashHex else {
throw ValidationError.invalidChain
}
previousHeader = blockHeader
}
}

}

extension BlockValidator {

enum ValidationError: Error {
case forkDetected
case invalidChain
case invalidProofOfWork
}

}

0 comments on commit dc16f81

Please sign in to comment.