Last active
May 19, 2017 04:54
-
-
Save dckc/a49b51bbe014f09ab8f762d377f71958 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// transcription of money example from "Smart Contracts" | |
// http://www.erights.org/smart-contracts/index.html | |
// http://www.erights.org/elib/capability/ode/ode-capabilities.html | |
// http://www.madmode.com/2011/11/capability-security-in-e-coffescript.html | |
// https://bitbucket.org/DanC/coffee-craft/src/682d06f02e99/money.coffee?fileviewer=file-view-default | |
// typealias not allowed inside class | |
typealias Decr = (Int) -> Unit | |
class Mint(val name: String) { | |
// destructuring assignment can only be used on local vars :-/ | |
val sealer: Sealer<Decr> | |
val unsealer: Unsealer<Decr> | |
init { | |
val (s, u) = Brand<Decr>(name).run() | |
sealer = s | |
unsealer = u | |
} | |
inner class Purse(bal: Int) { // balance clashes with getBalance | |
override fun toString(): String = "<has $current $name bucks>" | |
var current: Int | |
init { | |
require(bal >= 0) | |
current = bal | |
} | |
val decr = { amount: Int -> | |
require(0 < amount && amount <= current) | |
current -= amount | |
} | |
fun getBalance(): Int = current | |
fun sprout() = Purse(0) | |
fun getDecr() = sealer.seal(decr) | |
fun deposit(amount: Int, src: Purse) { | |
unsealer.unseal(src.getDecr())(amount) | |
current += amount | |
} | |
} | |
override fun toString(): String ="<${name}'s mint>" | |
} | |
// let's see if I remember how to do this... | |
// nope. looked it up: | |
// http://wiki.erights.org/wiki/Walnut/Secure_Distributed_Computing/Capability_Patterns | |
// https://www.cypherpunks.com/erights/javadoc/org/erights/e/elib/sealing/Brand.html | |
interface SealedBox<T> { | |
fun shareContent() | |
} | |
interface Sealer<T> { | |
fun seal(obj: T): SealedBox<T> | |
} | |
interface Unsealer<T> { | |
fun unseal(box: SealedBox<T>): T | |
} | |
class Brand<T>(hint: String) { | |
private var shared: Option<T> = Option.None | |
private var contents: T? = null | |
inner class MySealedBox constructor(val it: T) : SealedBox<T> { | |
override fun toString(): String ="SealedBox()" | |
override fun shareContent() { | |
val s = Option.Some(it) | |
shared = s | |
} | |
} | |
inner class MySealer : Sealer<T> { | |
override fun seal(it: T): SealedBox<T> = MySealedBox(it) | |
} | |
inner class MyUnsealer : Unsealer<T> { | |
override fun unseal(box: SealedBox<T>): T { | |
shared = Option.None | |
box.shareContent() | |
// val s to avoid | |
// Error:(86, 35) Kotlin: Smart cast to 'Option.Some<T>' is impossible, | |
// because 'shared' is a mutable property that could have been changed by this time | |
val s = shared | |
contents = when (s) { | |
is Option.None -> throw IllegalStateException("invalid box") | |
is Option.Some -> s.value | |
} | |
shared = Option.None | |
return contents!! | |
} | |
} | |
fun run(): Pair<Sealer<T>, Unsealer<T>> { | |
return Pair(MySealer(), MyUnsealer()) | |
} | |
} | |
// https://hackernoon.com/kotlin-functors-applicatives-and-monads-in-pictures-part-1-3-c47a1b1ce251 | |
sealed class Option<out A> { | |
object None : Option<Nothing>() | |
data class Some<out A>(val value: A) : Option<A>() | |
inline fun <B> map(f: (A) -> B): Option<B> = when (this) { | |
is None -> this | |
is Some -> Some(f(value)) | |
} | |
} | |
fun main(args: Array<String>) { | |
// eyeball-test makeBrandPair | |
val (s, u) = Brand<String>("bob").run() | |
val x = s.seal("abc") | |
println(x) | |
println(u.unseal(x)) | |
// example from ode-capabilities.html | |
val carolMint = Mint("Carol") | |
println(carolMint) | |
// value: <Carol's mint> | |
val aliceMainPurse = carolMint.Purse(1000) | |
println(aliceMainPurse) | |
// value: <has 1000 Carol bucks> | |
val bobMainPurse = carolMint.Purse(0) | |
println(bobMainPurse) | |
// value: <has 0 Carol bucks> | |
val paymentForBob = aliceMainPurse.sprout() | |
// value: <has 0 Carol bucks> | |
paymentForBob.deposit(10, aliceMainPurse) | |
//Then, we send a foo request to Bob, providing the purse containing $10 as payment: | |
// bob.foo(..., paymentForBob, ...) | |
//What might Bob's foo method look like? | |
class Bob { | |
// ... | |
//fun foo(payment: Purse) ... { | |
// bobMainPurse.deposit(10, payment) | |
// # proceed only if we got $10 | |
// ... | |
} | |
// So playing Bob, we perform | |
bobMainPurse.deposit(10, paymentForBob) | |
// Our new balances are | |
println(bobMainPurse.getBalance()) | |
// value: 10 | |
println(aliceMainPurse.getBalance()) | |
// value: 990 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment