[marketplace] split ContractInteractions
Split ContractInteractions into: - ClientInteractions (with purchasing) - HostInteractions (with sales and proving)
This commit is contained in:
parent
9f02f90f68
commit
cff2ca93d8
|
@ -94,7 +94,10 @@ proc stop*(s: CodexServer) {.async.} =
|
|||
|
||||
s.runHandle.complete()
|
||||
|
||||
proc new(_: type ContractInteractions, config: CodexConf): ?ContractInteractions =
|
||||
proc new(_: type ContractInteractions,
|
||||
config: CodexConf,
|
||||
repo: RepoStore): Contracts =
|
||||
|
||||
if not config.persistence:
|
||||
if config.ethAccount.isSome:
|
||||
warn "Ethereum account was set, but persistence is not enabled"
|
||||
|
@ -104,10 +107,16 @@ proc new(_: type ContractInteractions, config: CodexConf): ?ContractInteractions
|
|||
error "Persistence enabled, but no Ethereum account was set"
|
||||
quit QuitFailure
|
||||
|
||||
var client: ?ClientInteractions
|
||||
var host: ?HostInteractions
|
||||
if deployment =? config.ethDeployment:
|
||||
ContractInteractions.new(config.ethProvider, account, deployment)
|
||||
client = ClientInteractions.new(config.ethProvider, account, deployment)
|
||||
host = HostInteractions.new(config.ethProvider, account, repo, deployment)
|
||||
else:
|
||||
ContractInteractions.new(config.ethProvider, account)
|
||||
client = ClientInteractions.new(config.ethProvider, account)
|
||||
host = HostInteractions.new(config.ethProvider, account, repo)
|
||||
|
||||
(client, host)
|
||||
|
||||
proc new*(T: type CodexServer, config: CodexConf, privateKey: CodexPrivateKey): T =
|
||||
|
||||
|
|
|
@ -1,78 +1,5 @@
|
|||
import pkg/ethers
|
||||
import pkg/chronicles
|
||||
import ../purchasing
|
||||
import ../sales
|
||||
import ../proving
|
||||
import ./deployment
|
||||
import ./marketplace
|
||||
import ./market
|
||||
import ./proofs
|
||||
import ./clock
|
||||
import ./interactions/interactions
|
||||
import ./interactions/hostinteractions
|
||||
import ./interactions/clientinteractions
|
||||
|
||||
export purchasing
|
||||
export sales
|
||||
export proving
|
||||
export chronicles
|
||||
|
||||
type
|
||||
ContractInteractions* = ref object
|
||||
purchasing*: Purchasing
|
||||
sales*: Sales
|
||||
proving*: Proving
|
||||
clock: OnChainClock
|
||||
|
||||
proc new*(_: type ContractInteractions,
|
||||
signer: Signer,
|
||||
deployment: Deployment): ?ContractInteractions =
|
||||
|
||||
without address =? deployment.address(Marketplace):
|
||||
error "Unable to determine address of the Marketplace smart contract"
|
||||
return none ContractInteractions
|
||||
|
||||
let contract = Marketplace.new(address, signer)
|
||||
let market = OnChainMarket.new(contract)
|
||||
let proofs = OnChainProofs.new(contract)
|
||||
let clock = OnChainClock.new(signer.provider)
|
||||
let proving = Proving.new(proofs, clock)
|
||||
some ContractInteractions(
|
||||
purchasing: Purchasing.new(market, clock),
|
||||
sales: Sales.new(market, clock, proving),
|
||||
proving: proving,
|
||||
clock: clock
|
||||
)
|
||||
|
||||
proc new*(_: type ContractInteractions,
|
||||
providerUrl: string,
|
||||
account: Address,
|
||||
deploymentFile: string = string.default): ?ContractInteractions =
|
||||
|
||||
let provider = JsonRpcProvider.new(providerUrl)
|
||||
let signer = provider.getSigner(account)
|
||||
|
||||
var deploy: Deployment
|
||||
try:
|
||||
if deploymentFile == string.default:
|
||||
deploy = deployment()
|
||||
else:
|
||||
deploy = deployment(deploymentFile)
|
||||
except IOError as e:
|
||||
error "Unable to read deployment json", msg = e.msg
|
||||
return none ContractInteractions
|
||||
|
||||
ContractInteractions.new(signer, deploy)
|
||||
|
||||
proc new*(_: type ContractInteractions,
|
||||
account: Address): ?ContractInteractions =
|
||||
ContractInteractions.new("ws://localhost:8545", account)
|
||||
|
||||
proc start*(interactions: ContractInteractions) {.async.} =
|
||||
await interactions.clock.start()
|
||||
await interactions.sales.start()
|
||||
await interactions.proving.start()
|
||||
await interactions.purchasing.start()
|
||||
|
||||
proc stop*(interactions: ContractInteractions) {.async.} =
|
||||
await interactions.purchasing.stop()
|
||||
await interactions.sales.stop()
|
||||
await interactions.proving.stop()
|
||||
await interactions.clock.stop()
|
||||
export interactions, hostinteractions, clientinteractions
|
|
@ -0,0 +1,55 @@
|
|||
import pkg/ethers
|
||||
import pkg/chronicles
|
||||
|
||||
import ../../purchasing
|
||||
import ../deployment
|
||||
import ../marketplace
|
||||
import ../market
|
||||
import ../proofs
|
||||
import ../clock
|
||||
import ./interactions
|
||||
|
||||
export purchasing
|
||||
export chronicles
|
||||
|
||||
type
|
||||
ClientInteractions* = ref object of ContractInteractions
|
||||
purchasing*: Purchasing
|
||||
|
||||
proc new*(_: type ClientInteractions,
|
||||
signer: Signer,
|
||||
deployment: Deployment): ?ClientInteractions =
|
||||
|
||||
without address =? deployment.address(Marketplace):
|
||||
error "Unable to determine address of the Marketplace smart contract"
|
||||
return none ClientInteractions
|
||||
|
||||
let contract = Marketplace.new(address, signer)
|
||||
let market = OnChainMarket.new(contract)
|
||||
let clock = OnChainClock.new(signer.provider)
|
||||
|
||||
let c = ClientInteractions.new(clock)
|
||||
c.purchasing = Purchasing.new(market, clock)
|
||||
some c
|
||||
|
||||
proc new*(_: type ClientInteractions,
|
||||
providerUrl: string,
|
||||
account: Address,
|
||||
deploymentFile: string = string.default): ?ClientInteractions =
|
||||
|
||||
without prepared =? prepare(providerUrl, account, deploymentFile):
|
||||
return none ClientInteractions
|
||||
|
||||
ClientInteractions.new(prepared.signer, prepared.deploy)
|
||||
|
||||
proc new*(_: type ClientInteractions,
|
||||
account: Address): ?ClientInteractions =
|
||||
ClientInteractions.new("ws://localhost:8545", account)
|
||||
|
||||
proc start*(self: ClientInteractions) {.async.} =
|
||||
await self.purchasing.start()
|
||||
await procCall ContractInteractions(self).start()
|
||||
|
||||
proc stop*(self: ClientInteractions) {.async.} =
|
||||
await self.purchasing.stop()
|
||||
await procCall ContractInteractions(self).stop()
|
|
@ -0,0 +1,67 @@
|
|||
import pkg/ethers
|
||||
import pkg/chronicles
|
||||
|
||||
import ../../sales
|
||||
import ../../proving
|
||||
import ../../stores
|
||||
import ../deployment
|
||||
import ../marketplace
|
||||
import ../market
|
||||
import ../proofs
|
||||
import ../clock
|
||||
import ./interactions
|
||||
|
||||
export sales
|
||||
export proving
|
||||
export chronicles
|
||||
|
||||
type
|
||||
HostInteractions* = ref object of ContractInteractions
|
||||
sales*: Sales
|
||||
proving*: Proving
|
||||
|
||||
proc new*(_: type HostInteractions,
|
||||
signer: Signer,
|
||||
deployment: Deployment,
|
||||
repoStore: RepoStore): ?HostInteractions =
|
||||
|
||||
without address =? deployment.address(Marketplace):
|
||||
error "Unable to determine address of the Marketplace smart contract"
|
||||
return none HostInteractions
|
||||
|
||||
let contract = Marketplace.new(address, signer)
|
||||
let market = OnChainMarket.new(contract)
|
||||
let proofs = OnChainProofs.new(contract)
|
||||
let clock = OnChainClock.new(signer.provider)
|
||||
let proving = Proving.new(proofs, clock)
|
||||
|
||||
let h = HostInteractions.new(clock)
|
||||
h.sales = Sales.new(market, clock, proving, repoStore)
|
||||
h.proving = proving
|
||||
some h
|
||||
|
||||
proc new*(_: type HostInteractions,
|
||||
providerUrl: string,
|
||||
account: Address,
|
||||
repo: RepoStore,
|
||||
deploymentFile: string = string.default): ?HostInteractions =
|
||||
|
||||
without prepared =? prepare(providerUrl, account, deploymentFile):
|
||||
return none HostInteractions
|
||||
|
||||
HostInteractions.new(prepared.signer, prepared.deploy, repo)
|
||||
|
||||
proc new*(_: type HostInteractions,
|
||||
account: Address,
|
||||
repo: RepoStore): ?HostInteractions =
|
||||
HostInteractions.new("ws://localhost:8545", account, repo)
|
||||
|
||||
method start*(self: HostInteractions) {.async.} =
|
||||
await self.sales.start()
|
||||
await self.proving.start()
|
||||
await procCall ContractInteractions(self).start()
|
||||
|
||||
method stop*(self: HostInteractions) {.async.} =
|
||||
await self.sales.stop()
|
||||
await self.proving.stop()
|
||||
await procCall ContractInteractions(self).start()
|
|
@ -0,0 +1,45 @@
|
|||
import pkg/ethers
|
||||
import pkg/chronicles
|
||||
import pkg/questionable
|
||||
import pkg/questionable/results
|
||||
import ../../errors
|
||||
import ../deployment
|
||||
import ../clock
|
||||
|
||||
type
|
||||
ContractInteractions* = ref object of RootObj
|
||||
clock: OnChainClock
|
||||
ContractInteractionsError* = object of CodexError
|
||||
ReadDeploymentFileFailureError* = object of ContractInteractionsError
|
||||
|
||||
method new*[T: ContractInteractions](_: type T, clock: OnChainClock): T {.base.} =
|
||||
T(clock: clock)
|
||||
|
||||
proc prepare*(
|
||||
providerUrl: string = "ws://localhost:8545",
|
||||
account: Address,
|
||||
deploymentFile: string = string.default):
|
||||
?!tuple[signer: JsonRpcSigner, deploy: Deployment] =
|
||||
|
||||
let provider = JsonRpcProvider.new(providerUrl)
|
||||
let signer = provider.getSigner(account)
|
||||
|
||||
var deploy: Deployment
|
||||
try:
|
||||
if deploymentFile == string.default:
|
||||
deploy = deployment()
|
||||
else:
|
||||
deploy = deployment(deploymentFile)
|
||||
except IOError as e:
|
||||
let err = newException(ReadDeploymentFileFailureError,
|
||||
"Unable to read deployment json")
|
||||
err.parent = e
|
||||
return failure(err)
|
||||
|
||||
return success((signer, deploy))
|
||||
|
||||
method start*(interactions: ContractInteractions) {.async, base.} =
|
||||
await interactions.clock.start()
|
||||
|
||||
method stop*(interactions: ContractInteractions) {.async, base.} =
|
||||
await interactions.clock.stop()
|
|
@ -43,6 +43,10 @@ type
|
|||
|
||||
CodexError = object of CatchableError
|
||||
|
||||
Contracts* = tuple
|
||||
client: ?ClientInteractions
|
||||
host: ?HostInteractions
|
||||
|
||||
CodexNodeRef* = ref object
|
||||
switch*: Switch
|
||||
networkId*: PeerID
|
||||
|
@ -50,7 +54,7 @@ type
|
|||
engine*: BlockExcEngine
|
||||
erasure*: Erasure
|
||||
discovery*: Discovery
|
||||
contracts*: ?ContractInteractions
|
||||
contracts*: Contracts
|
||||
|
||||
proc findPeer*(
|
||||
node: CodexNodeRef,
|
||||
|
@ -250,7 +254,7 @@ proc requestStorage*(self: CodexNodeRef,
|
|||
##
|
||||
trace "Received a request for storage!", cid, duration, nodes, tolerance, reward
|
||||
|
||||
without contracts =? self.contracts:
|
||||
without contracts =? self.contracts.client:
|
||||
trace "Purchasing not available"
|
||||
return failure "Purchasing not available"
|
||||
|
||||
|
@ -307,7 +311,7 @@ proc new*(
|
|||
engine: BlockExcEngine,
|
||||
erasure: Erasure,
|
||||
discovery: Discovery,
|
||||
contracts = ContractInteractions.none): T =
|
||||
contracts: Contracts = (ClientInteractions.none, HostInteractions.none)): T =
|
||||
T(
|
||||
switch: switch,
|
||||
blockStore: store,
|
||||
|
@ -329,7 +333,7 @@ proc start*(node: CodexNodeRef) {.async.} =
|
|||
if not node.discovery.isNil:
|
||||
await node.discovery.start()
|
||||
|
||||
if contracts =? node.contracts:
|
||||
if contracts =? node.contracts.host:
|
||||
# TODO: remove Sales callbacks, pass BlockStore and StorageProofs instead
|
||||
contracts.sales.onStore = proc(request: StorageRequest,
|
||||
slot: UInt256,
|
||||
|
@ -369,7 +373,7 @@ proc start*(node: CodexNodeRef) {.async.} =
|
|||
await contracts.start()
|
||||
except CatchableError as error:
|
||||
error "Unable to start contract interactions: ", error=error.msg
|
||||
node.contracts = ContractInteractions.none
|
||||
node.contracts.host = HostInteractions.none
|
||||
|
||||
node.networkId = node.switch.peerInfo.peerId
|
||||
notice "Started codex node", id = $node.networkId, addrs = node.switch.peerInfo.addrs
|
||||
|
@ -389,8 +393,11 @@ proc stop*(node: CodexNodeRef) {.async.} =
|
|||
if not node.discovery.isNil:
|
||||
await node.discovery.stop()
|
||||
|
||||
if contracts =? node.contracts:
|
||||
await contracts.stop()
|
||||
if clientContracts =? node.contracts.client:
|
||||
await clientContracts.stop()
|
||||
|
||||
if hostContracts =? node.contracts.host:
|
||||
await hostContracts.stop()
|
||||
|
||||
if not node.blockStore.isNil:
|
||||
await node.blockStore.close
|
||||
|
|
|
@ -244,7 +244,7 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
|
|||
"/api/codex/v1/sales/availability") do () -> RestApiResponse:
|
||||
## Returns storage that is for sale
|
||||
|
||||
without contracts =? node.contracts:
|
||||
without contracts =? node.contracts.host:
|
||||
return RestApiResponse.error(Http503, "Sales unavailable")
|
||||
|
||||
let json = %contracts.sales.available
|
||||
|
@ -259,7 +259,7 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
|
|||
## duration - maximum time the storage should be sold for (in seconds)
|
||||
## minPrice - minimum price to be paid (in amount of tokens)
|
||||
|
||||
without contracts =? node.contracts:
|
||||
without contracts =? node.contracts.host:
|
||||
return RestApiResponse.error(Http503, "Sales unavailable")
|
||||
|
||||
let body = await request.getBody()
|
||||
|
@ -281,7 +281,7 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
|
|||
"/api/codex/v1/storage/purchases/{id}") do (
|
||||
id: PurchaseId) -> RestApiResponse:
|
||||
|
||||
without contracts =? node.contracts:
|
||||
without contracts =? node.contracts.client:
|
||||
return RestApiResponse.error(Http503, "Purchasing unavailable")
|
||||
|
||||
without id =? id.tryGet.catch, error:
|
||||
|
|
|
@ -1,32 +1,63 @@
|
|||
import std/os
|
||||
import codex/contracts
|
||||
|
||||
import pkg/datastore
|
||||
|
||||
import pkg/codex/contracts
|
||||
import pkg/codex/stores
|
||||
|
||||
import ../ethertest
|
||||
import ./examples
|
||||
|
||||
ethersuite "Marketplace Contract Interactions":
|
||||
ethersuite "Marketplace Contract Client Interactions":
|
||||
|
||||
let account = Address.example
|
||||
|
||||
var contracts: ContractInteractions
|
||||
var contracts: ClientInteractions
|
||||
|
||||
setup:
|
||||
contracts = !ContractInteractions.new(account)
|
||||
contracts = !ClientInteractions.new(account)
|
||||
|
||||
test "can be instantiated with a signer and deployment info":
|
||||
let signer = provider.getSigner()
|
||||
let deployment = deployment()
|
||||
check ContractInteractions.new(signer, deployment).isSome
|
||||
check ClientInteractions.new(signer, deployment).isSome
|
||||
|
||||
test "can be instantiated with a provider url":
|
||||
let url = "http://localhost:8545"
|
||||
let account = Address.example
|
||||
let deployment = "vendor" / "codex-contracts-eth" / "deployment-localhost.json"
|
||||
check ContractInteractions.new(url, account).isSome
|
||||
check ContractInteractions.new(url, account, deployment).isSome
|
||||
check ClientInteractions.new(url, account).isSome
|
||||
check ClientInteractions.new(url, account, deployment).isSome
|
||||
|
||||
test "provides purchasing":
|
||||
check contracts.purchasing != nil
|
||||
|
||||
ethersuite "Marketplace Contract Host Interactions":
|
||||
|
||||
let account = Address.example
|
||||
|
||||
var
|
||||
contracts: HostInteractions
|
||||
repo: RepoStore
|
||||
|
||||
setup:
|
||||
let repoDs = SQLiteDatastore.new(Memory).tryGet()
|
||||
let metaDs = SQLiteDatastore.new(Memory).tryGet()
|
||||
repo = RepoStore.new(repoDs, metaDs)
|
||||
contracts = !HostInteractions.new(account, repo)
|
||||
|
||||
test "can be instantiated with a signer and deployment info":
|
||||
let signer = provider.getSigner()
|
||||
let deployment = deployment()
|
||||
check HostInteractions.new(signer, deployment, repo).isSome
|
||||
|
||||
test "can be instantiated with a provider url":
|
||||
let url = "http://localhost:8545"
|
||||
let account = Address.example
|
||||
let deployment = "vendor" / "codex-contracts-eth" / "deployment-localhost.json"
|
||||
check HostInteractions.new(url, account, repo).isSome
|
||||
check HostInteractions.new(url, account, repo, deployment).isSome
|
||||
|
||||
test "provides sales":
|
||||
check contracts.sales != nil
|
||||
|
||||
|
|
Loading…
Reference in New Issue