Skip to content

Instantly share code, notes, and snippets.

@birchmd
Last active September 11, 2018 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save birchmd/f25578323b249ae03a45499a8165ab9d to your computer and use it in GitHub Desktop.
Save birchmd/f25578323b249ae03a45499a8165ab9d to your computer and use it in GitHub Desktop.
Scala code making use of rchain project resources to generate Rholang that performs transfers
import coop.rchain.casper.genesis.contracts.{Rev, Wallet}
import coop.rchain.casper.util.rholang.InterpreterUtil.mkTerm
import coop.rchain.casper.util.rholang.RuntimeManager
import coop.rchain.crypto.codec.Base16
import coop.rchain.crypto.hash.Blake2b256
import coop.rchain.crypto.signatures.Ed25519
import coop.rchain.rholang.interpreter.Runtime
import coop.rchain.shared.PathOps.RichPath
import java.io.PrintWriter
import java.nio.file.Files
import monix.execution.Scheduler.Implicits.global
import Wallet._
object RChainWalletTransfers {
//give a simple address for a wallet
def depositAddress(wallet: Wallet): String = "0x" + rhoPublicName(wallet).split(':').last.dropRight(1)
//generate the rholang code for accepting purses at an address
def depositForwarder(wallet: Wallet): String = {
val address = depositAddress(wallet)
s"""
contract @"$address"(@purse) = {
new purseAmountCh, return(`rho:io:stdout`) in {
@(purse, "getBalance")!(*purseAmountCh) |
for(@wallet <- ${rhoPublicName(wallet)}; @amount <- purseAmountCh) {
@(wallet, "deposit")!(amount, purse, *return)
}
}
}
"""
}
//generate rholang code for transferring rev between wallets
def transfer(from: Wallet, to: Wallet, amount: Int, nonce: Int, sk: Array[Byte])(implicit rm: RuntimeManager): String = {
val destName = depositAddress(to)
val sigData = rm.captureResults(rm.emptyStateHash, mkTerm(s""" @"__SCALA__"!([$nonce, $amount, "$destName"].toByteArray()) """).right.get).head.exprs.head.getGByteArray
val sig = Base16.encode(Ed25519.sign(Blake2b256.hash(sigData.toByteArray), sk))
s"""
for(@wallet <- ${rhoPublicName(from)}) {
new status(`rho:io:stdout`) in {
@(wallet, "transfer")!($amount, $nonce, "$sig", "$destName", *status)
}
}
"""
}
def writeToFile(code: String, name: String): Unit = {
val out = new PrintWriter(s"./$name.rho")
out.println(code)
out.close()
}
def main(args: Array[String]): Unit = {
//main method to actually generate the rholang code
val runtimeDir = Files.createTempDirectory("casper-rholang-interpreter-")
val runtime = Runtime.create(runtimeDir, 1024L * 1024 * 10)
implicit val runtimeManager = RuntimeManager.fromRuntime(runtime)
val n: Int = args.head.toInt //number of wallets to make
val (sks, pks) = (1 to n).map(_ => Ed25519.newKeyPair).unzip
val wallets = pks.map(pk => Wallet("ed25519", Base16.encode(pk), 100))
val rev = new Rev[Wallet](Wallet.rhoCode, wallets)
val depositForwarders = wallets.map(depositForwarder)
val transfers = { //set up transfers between wallets; could be modified to do more txns
val wsks = wallets.zip(sks)
wsks.zip(wallets.tail).map {
case ((from, sk), to) => transfer(from, to, 11, 0, sk)
}
}
//Note that this generated code assumes NonNegativeNumber.rho, MakeMint.rho and BasicWallet.rho
//are already deployed. This is is the case for node instances because those contracts are in
//the genesis block.
val walletSeupCode = (rev.code +: depositForwarders).mkString(" |\n")
val transferCode = transfers.mkString(" |\n")
writeToFile(walletSeupCode, "walletSeup")
writeToFile(transferCode, "transfers")
runtime.close()
runtimeDir.recursivelyDelete()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment