oracle连接外部数据库_使用Oracle验证外部数据

oracle连接外部数据库

我经常在Corda Slack频道中闲逛,并尽可能回答问题。 我尝试回答的合理数量的问题与Oracle有关。 更具体地说,何时使用。 我觉得我可以回答,“当您需要验证可能经常更改的外部数据时使用Oracle”。 我大概在某个时候写了一个类似的答案。 我没办法做的...告诉某人如何实施。 因此,要纠正这一点。 我写这篇文章的目的是学习如何实现自己,并与您和我未来的自我分享这些知识。

何时使用Oracle

让我们从扩展何时使用Oracle开始。 就像我刚才提到的那样,当您需要验证可能经常更改的外部数据时,应该使用Oracle。 这可能是诸如汇率,股票价格之类的数据,甚至是我的博客当前处于上升还是下降状态(尽管我还没有看到它下降过!)。 我认为经常性部分在这里很重要。 如果数据很少更改,则针对包含与Oracle自己检索的相同类型的值的附件验证某些数据可能是可行的。 这就是为什么我认为仅应由Oracle来验证汇率等数据的原因。 话虽如此,它实际上取决于您的特定用例。

如何使用Oracle

Oracle如何进行此验证? 好吧,这取决于您。 但是,它可能会遵循以下步骤:

  • 从节点接收数据
  • 检索外部数据
  • 根据外部数据验证接收到的数据
  • 提供交易签名

这些是我认为大多数Oracle实现将包含的步骤。 可以添加更多步骤,并且完成的验证可以与用例要求一样复杂或简单。 尽管可以增加更多的步骤,但我真的怀疑,排除上面显示的任何步骤的Oracle是否会有很多用途。

上面显示的所有步骤仅从Oracle的角度显示了该过程。 还有很多事情要做,所以我认为一个好的图表可以帮助我们。 它还将继续介绍我将在本文中使用的示例。


序列图显示了与Oracle交互的过程

这些步骤中有很多是通用步骤,无论您将其放在何处,都将执行这些步骤。 在本节中,我将扩展并显示实现图中所示流程所涉及的代码。 因此,值得一看。。。我也花了很多时间使它看起来不错,所以请看一下!!

哦,在我继续之前还有一点。 我想强调一下将时序图组合起来对Corda Flows建模有多大帮助。 它确实突出显示了参与人员,需要进行多少次网络跳跃以及每个参与者进行了多少工作。 此外,它们是向只对您正在设计和/或实现的更高层次的流程感兴趣的人解释发生了什么的好方法。

客户端/不是Oracle端

如前所述,这里的某些代码是通用代码,您很可能会将其放入编写的任何Flow中。 我已经展示了所有内容,因此对于正在发生的事情没有任何歧义,但是我将仅针对需要突出显示的点进行扩展,因为它们包含特定于与Oracle交互的代码。

@InitiatingFlow
@StartableByRPC
class GiveAwayStockFlow(private val symbol: String,private val amount: Long,private val recipient: String
) :FlowLogic<SignedTransaction>() {@Suspendableoverride fun call(): SignedTransaction {val recipientParty = party()val oracle = oracle()val transaction =collectRecipientSignature(verifyAndSign(transaction(recipientParty, oracle)),recipientParty)val allSignedTransaction = collectOracleSignature(transaction, oracle)return subFlow(FinalityFlow(allSignedTransaction))}private fun party(): Party =serviceHub.networkMapCache.getPeerByLegalName(CordaX500Name.parse(recipient))?: throw IllegalArgumentException("Party does not exist")private fun oracle(): Party = serviceHub.networkMapCache.getPeerByLegalName(CordaX500Name("Oracle","London","GB"))?: throw IllegalArgumentException("Oracle does not exist")@Suspendableprivate fun collectRecipientSignature(transaction: SignedTransaction,party: Party): SignedTransaction {val signature = subFlow(CollectSignatureFlow(transaction,initiateFlow(party),party.owningKey)).single()return transaction.withAdditionalSignature(signature)}private fun verifyAndSign(transaction: TransactionBuilder): SignedTransaction {transaction.verify(serviceHub)return serviceHub.signInitialTransaction(transaction)}private fun transaction(recipientParty: Party, oracle: Party): TransactionBuilder =TransactionBuilder(notary()).apply {val priceOfStock = priceOfStock()addOutputState(state(recipientParty, priceOfStock), StockContract.CONTRACT_ID)addCommand(GiveAway(symbol, priceOfStock),listOf(recipientParty, oracle).map(Party::owningKey))}private fun priceOfStock(): Double =serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).priceprivate fun state(party: Party, priceOfStock: Double): StockGiftState =StockGiftState(symbol = symbol,amount = amount,price = priceOfStock * amount,recipient = party)private fun notary(): Party = serviceHub.networkMapCache.notaryIdentities.first()@Suspendableprivate fun collectOracleSignature(transaction: SignedTransaction,oracle: Party): SignedTransaction {val filtered = filteredTransaction(transaction, oracle)val signature = subFlow(CollectOracleStockPriceSignatureFlow(oracle, filtered))return transaction.withAdditionalSignature(signature)}private fun filteredTransaction(transaction: SignedTransaction,oracle: Party): FilteredTransaction =transaction.buildFilteredTransaction(Predicate {when (it) {is Command<*> -> oracle.owningKey in it.signers && it.value is GiveAwayelse -> false}})
}@InitiatedBy(GiveAwayStockFlow::class)
class SendMessageResponder(val session: FlowSession) : FlowLogic<Unit>() {@Suspendableoverride fun call() {subFlow(object : SignTransactionFlow(session) {override fun checkTransaction(stx: SignedTransaction) {}})}
}

首先,让我们看一下如何构建事务:

private fun transaction(recipientParty: Party, oracle: Party): TransactionBuilder =TransactionBuilder(notary()).apply {val priceOfStock = priceOfStock()addOutputState(state(recipientParty, priceOfStock), StockContract.CONTRACT_ID)addCommand(GiveAway(symbol, priceOfStock),listOf(recipientParty, oracle).map(Party::owningKey))}private fun priceOfStock(): Double =serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).price

这与我创建不涉及Oracle的事务的方式没有太大不同。 仅有的两个区别是,从外部来源(隐藏在StockRetriever服务内部)检索股票价格,并在Command中包括Oracle的签名。 这些代码添加与使用Oracle的原因一致。 外部数据包含在事务中,Oracle需要验证它是否正确。 为了证明Oracle认为交易有效,我们需要其签名。

我们将仔细研究分别检索外部数据的方法。

接下来是收集收件人签名:

@Suspendable
private fun collectRecipientSignature(transaction: SignedTransaction,party: Party
): SignedTransaction {val signature = subFlow(CollectSignatureFlow(transaction,initiateFlow(party),party.owningKey)).single()return transaction.withAdditionalSignature(signature)
}

收集交易对手的签名并不是Flow真正不平凡的一步,但CollectSignatureFlow不同的是,使用CollectSignatureFlow而不是通常使用的CollectSignaturesFlow (注意中间缺少“ s”)。 这是由于在事务中需要Oracle的签名。 将调用CollectSignaturesFlow来从所有必需的签名者(包括Oracle)中检索签名。 这将Oracle视为“正常”参与者。 这不是我们想要的。 取而代之的是,我们需要分别手动获取接收者和Oracle的签名。 手动部分是使用transaction.withAdditionalSignature

现在,收件人已经签署了交易,Oracle需要对其进行签名:

@Suspendable
private fun collectOracleSignature(transaction: SignedTransaction,oracle: Party
): SignedTransaction {val filtered = filteredTransaction(transaction, oracle)val signature = subFlow(CollectOracleStockPriceSignatureFlow(oracle, filtered))return transaction.withAdditionalSignature(signature)
}private fun filteredTransaction(transaction: SignedTransaction,oracle: Party
): FilteredTransaction =transaction.buildFilteredTransaction(Predicate {when (it) {is Command<*> -> oracle.owningKey in it.signers && it.value is GiveAwayelse -> false}})

在将事务发送给Oracle之前,建议对其进行过滤,以删除Oracle不需要的任何信息。 这可以防止Oracle看到不应共享的信息。 请记住,Oracle可能是另一个组织控制的节点,而不是您试图与其共享状态和事务的参与者。

SignedTransaction提供了buildFilteredTransaction函数,该函数仅包含与传入的谓词匹配的对象。在上面的示例中,它过滤掉了GiveAway (我创建的命令)命令之外的所有命令,该命令还必须具有Oracle作为签名者。

这将输出一个FilteredTransaction ,并传递给CollectOracleStockPriceSignatureFlow

@InitiatingFlow
class CollectOracleStockPriceSignatureFlow(private val oracle: Party,private val filtered: FilteredTransaction
) : FlowLogic<TransactionSignature>() {@Suspendableoverride fun call(): TransactionSignature {val session = initiateFlow(oracle)return session.sendAndReceive<TransactionSignature>(filtered).unwrap { it }}
}

这些代码所做的全部工作就是将FilteredTransaction发送到Oracle并等待其签名。 此处的代码可以放入主流程中,但是在可以的情况下将代码拆分出来是非常好的。

最后,从Oracle返回的TransactionSignature会以与接收者的签名之前添加方式相同的方式添加到事务中。 至此,由于所有必需的签名者都已经做好了自己的准备,因此可以准备提交交易了。

Oracle方面

既然我们已经涵盖了代码的客户端,我们就需要研究一下Oracle如何验证事务。 以下是Oracle代码的内容:

@InitiatedBy(CollectOracleStockPriceSignatureFlow::class)
class OracleStockPriceSignatureResponder(private val session: FlowSession) : FlowLogic<Unit>() {@Suspendableoverride fun call() {val transaction = session.receive<FilteredTransaction>().unwrap { it }val key = key()val isValid = transaction.checkWithFun { element: Any ->when {element is Command<*> && element.value is GiveAway -> {val command = element.value as GiveAway(key in element.signers).also {validateStockPrice(command.symbol,command.price)}}else -> false}}if (isValid) {session.send(serviceHub.createSignature(transaction, key))} else {throw InvalidStockPriceFlowException("Transaction: ${transaction.id} is invalid")}}private fun key(): PublicKey = serviceHub.myInfo.legalIdentities.first().owningKeyprivate fun validateStockPrice(symbol: String, price: Double) = try {serviceHub.cordaService(StockPriceValidator::class.java).validate(symbol, price)} catch (e: IllegalArgumentException) {throw InvalidStockPriceFlowException(e.message)}
}

StockPriceValidator隐藏了一些应在此处的代码,该代码检索外部股票价格并将其与传递给Oracle的价格进行比较。 它没有太多的代码,其验证是基本的,因此我将不对其进行详细说明。 简短地说,我不妨现在展示一下:

@CordaService
class StockPriceValidator(private val serviceHub: AppServiceHub) :SingletonSerializeAsToken() {fun validate(symbol: String, price: Double) =serviceHub.cordaService(StockRetriever::class.java).getCurrent(symbol).let {require(price == it.price) { "The price of $symbol is ${it.price}, not $price" }}
}

返回到OracleStockPriceSignatureResponder 。 首先,调用receive来获取客户端发送的FilteredTransaction 。 然后使用其checkWithFun函数对其进行检查。 这是一个方便的函数,它查看每个对象并期望返回Boolean 。 使用此方法,如果事务中包含的所有内容都是GiveAway命令(其中Oracle是签名者),并且最重要的是检查该命令中包含的外部数据是否正确,则该事务被视为有效。 如果您回想起以前的代码,则会传入正确的命令和签名者。唯一剩下的验证是在外部数据上。 如果一切正常,那么Oracle将接受该事务并将其签名发送回请求该请求的客户端。

我选择通过引发异常(连同错误消息)来完成验证,然后将异常传播到请求方。 我认为,这使您更容易了解出了什么问题,以便可以正确地处理它,而不仅仅是直接的“失败验证”消息。 如果Oracle正在执行的验证很复杂,则这些错误消息将变得更加有价值。

检索外部数据

您应该已经看到StockRetriever类现在弹出两次。 请求方和Oracle中都使用了它。 我已经在两种类型的节点(普通节点和Oracle)之间共享了此代码,但这可能不适合您自己的用例。 此外,您如何选择检索外部数据取决于您,我只是提供一种可能的解决方案。

该代码可以在下面找到:

@CordaService
class StockRetriever(serviceHub: AppServiceHub) :SingletonSerializeAsToken() {private val client = OkHttpClient()private val mapper = ObjectMapper()fun getCurrent(symbol: String): Stock {val response = client.newCall(request(symbol)).execute()return response.body()?.let {val json = it.string()require(json != "Unknown symbol") { "Stock with symbol: $symbol does not exist" }val tree = mapper.readTree(json)Stock(symbol = symbol,name = tree["companyName"].asText(),primaryExchange = tree["primaryExchange"].asText(),price = tree["latestPrice"].asDouble())} ?: throw IllegalArgumentException("No response")}private fun request(symbol: String) =Request.Builder().url("https://api.iextrading.com/1.0/stock/$symbol/quote").build()
}

StockRetriever是一个很好的小服务,它使用OkHttpClient ( OkHttp )向API(由IEX Trading使用其Java库提供)发出HTTP请求,该API在提供股票代号时返回股票信息。 您可以使用任何想要发出HTTP请求的客户端。 我在一个示例CorDapp中看到了这个,并且我自己考虑了它。 就我个人而言,我也已经习惯了Spring,所以除了RestTemplate之外,我真的不认识其他任何客户。

返回响应后,它将转换为Stock对象,并传递回函数的调用者。 那是所有人。

结论

总之,当您的CorDapp需要频繁更改的外部数据且需要先进行验证才能提交事务时,应使用Oracle。 就像状态中保存的数据一样,外部数据非常重要,可能是最重要的,因为它很可能确定事务的主要内容。 因此,所有参与者都必须对数据正确无误感到欣慰,而不仅仅是凭空提出。 为此,Oracle还将检索外部数据,并根据事务表明数据应具有的内容对其进行验证。 此时,Oracle将签署交易或引发异常并将其视为无效。 由于不需要采取很多步骤,因此实现方面相当简单。 检索数据,将FilteredTransaction发送到包含将在其中进行验证的数据的Oracle。 是的,阅读本文后,您将了解更多内容。 但是,对于基本流程而言,就差不多了。 正如我在刚开始时所说的那样,Oracle如何进行验证可以根据需要简单或复杂。 虽然,我认为大多数将遵循此处所示的相同过程。

现在得出主要结论……总之,您现在已经掌握了在闲聊的渠道中回答有关Oracle的问题的知识,或者知道了如果不能将问题发送到哪里!

这篇文章中使用的代码可以在我的GitHub上找到 。

如果您发现此帖子有帮助,可以在Twitter上@LankyDanDev关注我,以了解我的新帖子。

翻译自: https://www.javacodegeeks.com/2019/01/validating-external-data-oracle.html

oracle连接外部数据库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332711.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

macOS如何格式化移动硬盘和U盘

1.打开磁盘工具 2.在左侧选择要格式化的外置磁盘设备&#xff0c;接着在右上角点击【抹掉】 3.点击【抹掉】会弹出如下的对话框&#xff0c;在格式中建议选择 ExFAT 格式&#xff0c;这是一个在 Windows 和 macOS 都可以使用的文件系统格式 选择好要格式化的文件系统格式后&…

macOS查看IP地址的命令

查看内网的 IP 地址&#xff1a; [~]$ ipconfig getifaddr en0 192.168.30.25 # 或者 [~]$ ifconfig en0 en0: flags8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500options400<CHANNEL_IO>ether d4:61:9d:11:c2:94 inet6 fe80::cbc:309b:57a4:5cf6…

mysql注入漏洞语句,web安全之sql注入漏洞

概念通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串&#xff0c;最终达到欺骗服务器执行恶意的SQL命令。通俗地讲&#xff0c;它是利用现有应用程序&#xff0c;将(恶意)的SQL命令注入到后台数据库引擎执行的能力&#xff0c;它可以通过在Web表单中输入(恶意…

ssrs 基于表达式显示_基于表达式的访问控制

ssrs 基于表达式显示1.概述 今天&#xff0c;我们将回顾基于表达式的访问控制&#xff08;EBAC&#xff09;&#xff0c;基于角色的访问控制&#xff08;RBAC&#xff09;和基于属性的访问控制&#xff08;ABAC&#xff09;之间的区别&#xff0c;并将重点放在EBAC上。 2.什么…

macOS下载、安装、使用tomcat服务器及IntelliJ IDEA for Mac 如何集成、配置、运行tomcat

文章目录web 服务器软件tomcat如何下载安装 tomcatmacOS 下如何启动 tomcatWindows 启动 tomcat部署项目的方式直接将项目放到 webapps 目录下即可在 tomcat 的配置文件 server.xml 中进行配置部署在 tomcat 的 localhost 目录下通过 xml 文件完成部署IntelliJ IDEA 集成 tomca…

run spark pi_Spark Run本地设计模式

run spark pi现在&#xff0c;许多Spark应用程序已成为遗留应用程序&#xff0c;很难在本地进行增强&#xff0c;测试和运行。 Spark具有很好的测试支持&#xff0c;但仍有许多Spark应用程序不可测试。 当您尝试运行一些旧的Spark应用程序时&#xff0c;我将分享一个常见错误…

php 表单 同步,Jquery点击按钮 异步和同步提交表单

最近在开发一个jsp学生信息管理系统&#xff0c;由于刚刚接触jsp&#xff0c;遇到问题比较多&#xff0c;特此记录与大家分享。Jquery ajax提交表单到servlet示例前台部分代码&#xff1a;姓名学号 ajax提交表单代码&#xff1a;//增加学生&#xff0c;异步提交学生表单$(&q…

IntelliJ IDEA for Mac如何配置数据源(Data Source)和用户驱动(User Driver)及数据库控制台_数据源配置(Console)详解

文章目录直接添加数据源&#xff08;Data Source&#xff09;添加驱动和数据源&#xff08;Driver and Data Source&#xff09;驱动数据库控制台直接添加数据源&#xff08;Data Source&#xff09; 直接添加数据源&#xff0c;IDE 会默认指定数据库驱动&#xff0c;如下图所示…

app aws_服务网格:Istio和AWS App Mesh

app aws本周在AWS re&#xff1a;Invent上的重大公告之一是AWS App Mesh 。 在谈论它之前&#xff0c;让我们先看一下网格到底是什么…… 什么是服务网格&#xff1f; 服务网格是微服务体系结构的基础结构层。 它处理服务之间的通信问题&#xff0c;使该通信更加可见&#xf…

php screw 密钥,php-screw php代码加密工具用法(整理)

1、进入http://sourceforge.net/projects/php-screw/下载最新版本php_screw-1.5.tar.gz 解压安装&#xff1a; #tar zxf php_screw-1.5.tar.gz #cd php_screw-1.5 #vi php_screw.h 将 #define PM9SCREW “\tPM9SCREW\t” #define PM9SCREW_LEN 10 修改为任意字串,如&#xff1a…

IntelliJ IDEA如何部署项目、部署方式以及部署相关的操作

文章目录工件列表工件类型添加工件部署项目exploded 工件的部署war 工件的部署手动部署项目war 包部署exploded 部署部署有关的操作deploy/redeploy&#xff08;部署/重新部署&#xff09;rerun/run&#xff08;重启服务器/启动服务器&#xff09;Update resources&#xff08;…

php恒等符,php学习笔记(三)操作符与控制结构

php学习笔记(三)操作符与控制结构更新时间&#xff1a;2011年08月06日 20:09:31 作者&#xff1a;好久没更新了&#xff0c;这段时间挺忙的。下面继续php学习 之 操作符与控制结构&#xff1b;一&#xff0e;字符串插入为了给开发人员处理字符串值提供最大的灵活性&#xff0…

spring框架三层架构_Spring框架架构

spring框架三层架构这是Spring Framework Architecture的概述。 了解Spring Framework的各个组成部分如何组织以及如何相互联系。 如果您想了解什么是Spring框架及其功能&#xff0c;请阅读Spring框架简介 。 总览 Spring是一个模块化框架 。 它不是作为一个软件包或多个模块捆…

IntelliJ IDEA for Mac如何管理SDK/JDK,模块如何设置SDK/JDK?

文章目录管理 IDE 中的 SDK设置模块依赖的 SDK管理 IDE 中的 SDK 设置模块依赖的 SDK

php 数组是否属于迭代器,数组的迭代器属性Iterator介绍

[导读]数组默认有迭代器属性数组默认有迭代器属性var arr [111,222,333];var aa arr[Symbol.iterator]();aa.next(); // { value: 111, done: false }aa.next(); // { value: 222, done: false }aa.next(); // { value: 333, done: false }aa.next(); // { value: undefined,…

elk 聚合日志_使用ELK堆栈进行日志聚合

elk 聚合日志1.简介 随着微服务的使用&#xff0c;创建稳定的分布式应用程序和摆脱许多遗留问题变得很容易。 但是微服务的使用也带来了一些挑战&#xff0c; 分布式日志管理就是其中之一。 由于微服务是隔离的&#xff0c;因此它们不共享数据库和日志文件&#xff0c;因此实时…

Java对象如何实现比较规则

文章目录一、Comparable二、Comparator示例代码一、Comparable public interface Comparable 此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序&#xff0c;类的 compareTo 方法被称为它的自然比较方法。 实现此接口的对象列表&#xff08;和数组…

python教材目录,python 目录

python在安装的时候&#xff0c;就自带了很多模块&#xff0c;我们把这些模块称之为标准库&#xff0c;其中&#xff0c;有一个是使用频率比较高的&#xff0c;就是 os 。这个库中方法和属性众多&#xff0c;有兴趣的看官可以参考官方文档&#xff1a;https://docs.python.org/…

quartus状态机生成_生成器作为(快速失败)状态机

quartus状态机生成这个想法是几周前在设计“生成器”类时想到的&#xff0c;该类必须将输入发送给封装的Writer 。 实际上&#xff0c;它是Builder模式。 但是&#xff0c;规则有些复杂&#xff0c;用户必须以某种方式调用add...()方法&#xff0c;才能正确生成输出。 不用说&…

除法算式的正确表述

12 4 3&#xff0c;这个关系表达式叫作除法算式&#xff0c;表述为 12 除以 4 等于 3&#xff1b;也可以表述为 4 除 12 等于 3。