Corda API:Contracts
原文地址:https://docs.corda.net/api-contracts.html
注意:阅读本文之前,你应该对 Corda 核心概念 - Contract 比较熟悉了。
Contract
Contracts 都是实现了 Contract
接口的类。Contract
接口定义如下:
/*** Implemented by a program that implements business logic on the shared ledger. All participants run this code for* every [net.corda.core.transactions.LedgerTransaction] they see on the network, for every input and output state. All* contracts must accept the transaction for it to be accepted: failure of any aborts the entire thing. The time is taken* from a trusted time-window attached to the transaction itself i.e. it is NOT necessarily the current time.** TODO: Contract serialization is likely to change, so the annotation is likely temporary.*/
@CordaSerializable
interface Contract {/*** Takes an object that represents a state transition, and ensures the inputs/outputs/commands make sense.* Must throw an exception if there's a problem that should prevent state transition. Takes a single object* rather than an argument so that additional data can be added without breaking binary compatibility with* existing contract code.*/@Throws(IllegalArgumentException::class)fun verify(tx: LedgerTransaction)
}
Contract
只有一个 verify
方法,它会有一个 LedgerTransaction
作为 input 参数并且不会返回任何内容。这个方法被用来检验一个交易的提议是否有效,包括下边的验证:
- 我们会搜集这个交易的 input 和 output states 的 contract code
- 我们会调用每个 contract code 的
verify
方法,将 transaction 作为 input 传进去 - 这个更新账本的提议仅仅在所有的
verify
方法都没有返回 exception 的情况下才算是有效的
verify
是在一个 sandbox 中执行的:
- 它没有权限访问内部的内容
- 针对于它可用的类库被放入白名单来不允许:网络访问像硬盘或数据库 I/O
这意味着 verify
仅仅能够在决定一个交易是否有效的时候才能够访问 LedgerTransaction
中定义的属性。
最简单的两个 verify
方法:
- 一个是接受所有可能的 transactions:
override fun verify(tx: TransactionForContract) {// Always accepts!
}
- 一个是拒绝所有的 transactions:
override fun verify(tx: TransactionForContract) {throw IllegalArgumentException("Always rejects!")
}
LedgerTransaction
被传入 verify 方法中的 LedgerTransaction
对象具有以下属性:
@CordaSerializable
data class LedgerTransaction @JvmOverloads constructor(/** The resolved input states which will be consumed/invalidated by the execution of this transaction. */override val inputs: List<StateAndRef<ContractState>>,override val outputs: List<TransactionState<ContractState>>,/** Arbitrary data passed to the program of each input state. */val commands: List<CommandWithParties<CommandData>>,/** A list of [Attachment] objects identified by the transaction that are needed for this transaction to verify. */val attachments: List<Attachment>,/** The hash of the original serialised WireTransaction. */override val id: SecureHash,override val notary: Party?,val timeWindow: TimeWindow?,val privacySalt: PrivacySalt,private val networkParameters: NetworkParameters? = null
) : FullTransaction() {
其中:
inputs
是类型为List<StateAndRef<ContractState>>
的 transaction 的 inputsoutputs
是类型为List<TransactionState<ContractState>>
的 transaction 的 outputscommands
是类型为List<CommandWithParties<CommandData>>
的 transaction 的 commands 和相关的签名者attachments
是类型为List<Attachment>
的 transaction 的 attachmentsnotary
是 transaction 的 notary。这个必须要同所有的 inputs 拥有相同的 notarytimeWindow
定义了一笔交易在什么样的时间窗(timewindow)内才会被公正(notarised)
LedgerTransaction
暴漏了很多 utility 方法来访问交易的内容:
inputStates
从StateAndRef
列表中获得 inputContractState
getInput
/getOutput
/getCommand
/getAttachment
通过索引(index)来获得某个组件getAttachment
通过 ID 获得一个附件inputsOfType
/inRefsOfType
/outputsOfType
/outRefsOfType
/commandsOfType
基于他们的类型获得相关组件filterInputs
/filterInRefs
/filterOutputs
/filterOutRefs
/filterCommands
基于一个条件获得相关组件findInput
/findInRef
/findOutput
/findOutRef
/findCommand
获得满足一定条件的单一组件,或者当有多个满足条件的组件的时候抛出异常
requireThat
verify
能够针对每一个约束手动地抛出异常:
override fun verify(tx: LedgerTransaction) {if (tx.inputs.size > 0)throw IllegalArgumentException("No inputs should be consumed when issuing an X.")if (tx.outputs.size != 1)throw IllegalArgumentException("Only one output state should be created.")
}
但是这个定义有些繁琐。我们可以使用 requireThat
来定义一系列的约束:
requireThat {"No inputs should be consumed when issuing an X." using (tx.inputs.isEmpty())"Only one output state should be created." using (tx.outputs.size == 1)val out = tx.outputs.single() as XState"The sender and the recipient cannot be the same entity." using (out.sender != out.recipient)"All of the participants must be signers." using (command.signers.containsAll(out.participants))"The X's value must be non-negative." using (out.x.value > 0)
}
对于 requireThat
中的每一个 <String
, Boolean
> 对来说,如果 boolean 条件返回的是 false,一个 IllegalArgumentException
会被抛出,包含对应的错误信息。所以这个错误会造成 transaction 被拒绝。
Commands
LedgerTransaction
包含了作为 CommandWithParties
实例列表的 commands。CommandWithParties
将一个 CommandData
和一个所需的签名者列表匹配起来:
/** A [Command] where the signing parties have been looked up if they have a well known/recognised institutional key. */
@CordaSerializable
data class CommandWithParties<out T : CommandData>(val signers: List<PublicKey>,/** If any public keys were recognised, the looked up institutions are available here */val signingParties: List<Party>,val value: T
)
其中:
signers
是每个签名者的PublicKey
的一个列表signingParties
签名者 identities 的列表,如果知道的话value
是被签名的对象(在这里指的是这个 command)
使用 commands 来处理 verify 分支
总的来说,我们希望基于交易的 commands 来定义不同的约束条件。比如我们想要为一个现金发行的 transaction 和 一个现金交换的 transaction 定义不同的合约。
我们可以通过提取这个 command 并在 verify
里使用标准的分支逻辑来实现这个功能。这里我们提取了交易中的类型为 XContract.Commands
的单独的 command,并且相应地对 verify
进行了分支逻辑判断:
class XContract : Contract {interface Commands : CommandData {class Issue : TypeOnlyCommandData(), Commandsclass Transfer : TypeOnlyCommandData(), Commands}override fun verify(tx: LedgerTransaction) {val command = tx.findCommand<Commands> { true }when (command) {is Commands.Issue -> {// Issuance verification logic.}is Commands.Transfer -> {// Transfer verification logic.}}}
}
Legal prose
一个 Contract 类可以使用 @LegalProseReference 的 annotation。这个 annotation 能够将这个 contract code 同以法律条款的形式定义的文档关联起来,这个文档中定义的是跟 verify 里所定义的约束内容相同的内容。这个并不是必须的,但是当出现意见不统一的情况下,法律条款文件效力会优先于软件中的实现。
@LegalProseReference 仅仅有一个 uri 的输入参数,作为同 contract code 相关联的法律条款文档的标识:
@LegalProseReference(uri = "foo.bar.com/my-legal-doc.html")
class MyContract : Contract {override fun verify(tx: LedgerTransaction) {// Contract logic.}
}
Corda API:Contracts相关推荐
- node.js入门 - 9.api:http
node一个重要任务是用来创建web服务,接下来我们就学习与此相关的一个重要的api -- http.我们使用http.createServer()创建一个http服务的实例,用来处理来自客户的请求. ...
- Netflix Play API:我们为什么构建了一个演进式架构?
在QCon SF大会上,Suudhan Rangarajan做了题为"Netflix Play API:我们为什么构建了一个演进式架构"的演讲.他演讲的要点包括:具有单一标识/职责 ...
- CV之API:利用Face++的人体识别接口,实现摄像头实时手势识别
CV之API:利用Face++的人体识别接口,实现摄像头实时手势识别 目录 测试图片 实现代码(部分) 测试图片 实现代码(部分) #利用Face++的人体识别接口,实现摄像头实时手势识别 impor ...
- TF学习——TF之API:TensorFlow的高级机器学习API—tf.contrib.learn的简介、使用方法、案例应用之详细攻略
TF学习--TF之API:TensorFlow的高级机器学习API-tf.contrib.learn的简介.使用方法.案例应用之详细攻略 目录 tf.contrib.learn的简介 tf.contr ...
- ML之API:国内外各大人工智能平台(百度云/华为云/阿里云/Face++等)及其API的简介、使用方法之详细攻略
ML之API:国内外各大人工智能平台(百度云/华为云/阿里云/Face++等)及其API的简介.使用方法之详细攻略 目录 一.百度云api 1.api之CV 二.旷视科技(face++)api 1.a ...
- OpenCV 高级API:TextDetectionModel和TextRecognitionModel
高级API:TextDetectionModel和TextRecognitionModel TextDetectionModel和TextRecognitionModel 介绍 预训练模型 测试图像 ...
- api如何使用_记录API:技术作家和工程师指南
在这门有关编写REST API文档的课程中,我不只是在谈论抽象概念,而是通过直接的动手方法将REST API关联起来.首先,您将通过使用简单的天气API在站点上放置天气预报来了解API文档. 使用AP ...
- WEB API:语音识别
2019独角兽企业重金招聘Python工程师标准>>> x-webkit-speech 语音输入功能: http://www.iinterest.net/2012/01/07/x-w ...
- Google API:如何访问Google Analytics(分析)数据?
在深入研究Google Analytics(分析)API之前,了解一些Google Analytics(分析)术语及其关系总是很有用的. Google帐户:要访问Google Analytics(分析 ...
最新文章
- sharepoint 备份还原
- Linux系统文件安全与权限
- 6个趣味项目,带你看看普通开发者如何玩转AI
- 基于stm32f107 stm32cube 和 LWIP 协议实现 udp 组播通信
- JavaScript+HTML设置视频预览图
- 实习二 分组密码加密_分组密码加密模式
- 盘点:最值得托付终身的星座
- 介绍MFSideMenu左右滑动控件的使用
- Mybatis源码阅读(二):动态节点解析2.2 —— SqlSourceBuilder与三种SqlSource
- 小甲鱼Python第二十二讲课后习题
- 【教程】Microsoft Wi-Fi Direct Virtual关闭方法
- HTML5编写船上航行,单体半滑行穿浪船船型与静水航行性能
- 万字长文!Go 后台项目架构思考与重构
- apache http server 停止工作_Tomcat9配置HTTP/2
- 日志服务(原SLS)新功能发布(5)--使用Logstash接入数据
- php svn更改密码,svn 开启修改备注
- vue+nodejs+element 实现drawio绘图效果
- mysql msi失败_MySQL .msi 安装失败改用.zip安装步骤
- 基于matlab的图像锐化,基于Matlab的图像锐化的研究
- Buzzsumo大型教程(内容营销+外链outreach必备)营销神器