由Trust Wallet理解以OA信用盘平台出售带杀大赔小功能太坊钱包管理和智能合约

钱包管理
钱包管理就要提到OA信用盘平台出售带杀大赔小功能QQ2952777280 话仙论坛http://hxforum.com 一个类EtherKeystore, 应用的核心业务的处理类, 有钱包管理(创建、删除、导入、导出)、助记词转化、签名工作、私钥管理等功能。
EtherKeystore中使用了由Trust开源的了两个库: TrustKeystore: 用于管理钱包的通用以太坊密钥库。TrustCore: 区块链核心的数据结构和算法。还有CryptoSwift, 一个标准的安全加密算法集合的库。

钱包创建
在EtherKeystore类中, 封装了钱包的创建, 主要使用了TrustKeystore库、TrustCore库中关于公私钥和地址的API、以及密码学的库CryptoSwift。我下面所说的整个流程也包括这些库中的源码逻辑, 先创建密钥对(或者助记词), 再利用本地生成的随机密码对密钥进行加密保存, 然后生成钱包, 将钱包、获取私钥的密码以及KeystoreKey保存到本地。

Trust默认的方式是生成助记词, 这种方式其实是私钥的一种管理方式, 助记词是由私钥通过某种算法派生出来的, TrustCore中的Crypto就是这个功能。而且当你用到私钥的时候, 你还可以把你的助记词通过对应的算法在转译成私钥。所以它只是一种私钥的存储方式, 下面文章中以私钥为例来讲述整个流程。

创建公钥私钥
创建钱包就相当于生成一对密钥, 公钥(PublicKey)和私钥(PrivateKey)。公钥其实就相当于你账户在区块链中的地址(Address); 私钥就相当于你钱包的账号密码, 它是证明你是钱包主人的唯一证明, 一旦丢失就不可找回。当然, 公钥并不完全等于地址, 地址是由公钥经过一系列的算法生成的, 需要经过SHA3-256(Keccak)哈希然后转化为符合EIP55规则的字符串。

(sk, pk) = generateKeys(keysize)
1
上面这段伪代码中, generateKeys方法把 keysize作为输入, 来产生一对公钥和私钥。私钥sk被安全保存,并用来签名一段消息;公钥pk是人人都可以找到的,拿到它,就可以用来验证你的签名。下图是TrustCore中对以太坊私钥和地址的keysize定义, 私钥是32字节, 公钥地址是20字节, 所以十六进制的私钥长度为64位, 而公钥地址长度为40位。

具体来说, 创建公钥和私钥的功能是由TrustCore中的PrivateKey来完成的。而且是通过苹果官方的Security库来创建的公钥和私钥, 经过整理密钥对生成和获取过程如下:

func getPrivatePublicKey() -> (String, String) {

let privateAttributes: [String: Any] = [
kSecAttrIsExtractable as String: true,
]
let parameters: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeyAttrs as String: privateAttributes,
]

// PrivateKey To String
guard let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, nil) else {
fatalError("Failed to generate key pair")
}
guard var priRepresentation = SecKeyCopyExternalRepresentation(privateKey, nil) as Data? else {
fatalError("Failed to extract new private key")
}
defer {
priRepresentation.replaceSubrange(0 ..< priRepresentation.count, with: repeatElement(0, count: priRepresentation.count))
}

let priData = Data(priRepresentation.suffix(32))
var priString = ""
for byte in priData {
priString.append(String(format: "%02x", byte))
}

// PublicKey To String
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
fatalError("Failed to get publickey")
}
guard var pubRepresentation = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? else {
fatalError("Failed to extract new public key")
}
defer {
pubRepresentation.replaceSubrange(0 ..< pubRepresentation.count, with: repeatElement(0, count: pubRepresentation.count))
}

let pubData = Data(pubRepresentation.suffix(32))
var pubString = ""
for byte in pubData {
pubString.append(String(format: "%02x", byte))
}

return (priString, pubString)
}

使用随机密码对私钥加密
在生成了私钥之后, 将在KeystoreKeyHeader类中, 这里使用了CryptoSwift(安全加密算法集合的库)对私钥进行加密。使用AES-128算法进行对称加密后, 将这些数据以KeystoreKeyHeader类型保存在KeystoreKey中。

创建 Wallet
在前两个步骤的基础之上, 就可以创建一个Wallet了, 并将Wallet加入到当前的账户中。也会计算或者获取一些参数存储在Wallet中, 如公钥地址Address, Account、KeystoreKey等。

保存到本地
KeyStore会将当前钱包账户的KeystoreKey数据存储在本地文件中。文件以"UTC+时间戳+钱包唯一标识"为名称存储在本地, 其中存储的是上面KeystoreKey的数据。这些数据用户每次启动时, 将会由这些数据再次生成所有的Wallet数据。
当然, 私钥当然也是需要保存的, 前一篇文章中说过了, 这样的敏感信息保存在keychain中。但keychain并不是直接存储这私钥, 而是将获取私钥的密码保存在其中了。以钱包的id为key值, 将获取私钥的密码保存子keychain之中, 拿出密码后, 再使用KeystoreKey进行AES-128对称解密, 获取私钥, 便可以使用了。所以, KeystoreKey这个类的主要功能是对私钥和助记词的管理以及对私钥的加解密。

另外, 这样拥有PrivateKey的钱包账户是不需要存储在Realm数据库中的。只有一种需要保存到本地的Realm数据库中, 那就是导入地址钱包, 下面将会说明。

钱包的导入
钱包导入相对于钱包的创建来说, 只是不需要自己去生成公钥和私钥对了, 剩下的流程还是一样的。当然导入时会有三种方式, 除了之前提到的私钥和助记词的方式, 还有地址的方式。
钱包地址是公开的, 当然你也可以导入, 也可以查看这个钱包的任何数据, 但因为你不具备它的私钥, 所以你不可以进行签名或者说任何写入区块链的操作。所以这种方式, 就不需要KeyStore进行操作了, 只需要EtherKeystore进行本地操作, 将其放入本地的Realm数据库中, 那就是导入地址钱包。当启动应用时, 将会以两者组成的数据为本地钱包列表。

钱包导出、删除等
钱包导出, 当然也会分三种方式, 私钥和助记词的方式, 还有地址的方式。在keychain中将密码取出, 然后通过KeystoreKey解密到私钥或者助记词, 导出。地址的方式, 就是直接导出地址。

如果你把上面的钱包创建条理理清楚了, 你就可以想到删除只是钱包创建的逆过程, 但没有那么复杂。只需要验证你的私钥是正确的就可以将你本地KeystoreKey删除了。

EtherKeystore 模块结构图
下图中画了 EtherKeystore在创建或者导入钱包时的流程, 可一清楚的看到这个模块的结构。绿色的部分是TrustCore和TrustKeystore库中的调用, 浅蓝色是数据层的一些处理。

智能合约
在前一篇文章中的网络层中, 对只能合约以及具体网络层业务逻辑没有做详细说明。这里将会讨论几个问题, 网络层具体方案, 以太坊智能合约的调用。

合约调用方式
在以太坊的官方文档中提供了两种 API, 一个种是JSON RPC API, 一种是JavaScript API。

JavaScript API
虽然看起来是两种 API, 其实后者是通过RPC调用与本地节点进行通信的。也就可以理解为 JavaScript API是对 JSON RPC API的封装, 方便了从JavaScript应用程序内部与ethereum节点通信。官方开源的库web3.js就是做了这个事情。

JSON RPC API
JSON-RPC是一种轻量级的远程过程调用(RPC)协议。该规范主要定义了一些数据结构和处理的规则。它与传输无关, 因为这些概念可以通过Socket、HTTP, 或者其它的消息传递环境中使用。它使用 JSON(RFC 4627)作为数据格式。

默认的JSON-RPC端点:

Client URL
C++ http://localhost:8545
Go http://localhost:8545
Py http://localhost:4000
Parity http://localhost:8545
RPC的支持:情况

cpp-ethereum go-ethereum py-ethereum parity
JSON-RPC 1.0 ?
JSON-RPC 2.0 ? ? ? ?
Batch requests ? ? ? ?
HTTP ? ? ? ?
IPC ? ? ?
WS ? ?
合约调用
当然, 在Trust的 iOS端是通过 JSON RPC Over HTTP的方式进行智能合约调用的。项目中针对合约调用的请求, 网络层的设计是 APIKit + JSONRPCKit 的方式。

JSON RPC Over HTTP
在项目中, 以太坊智能合约调用都是JSON RPC Over HTTP的方式, 而且所使用的以太坊节点前一篇文章网络层中就提到过。

var remoteURL: URL {
let urlString: String = {
switch self {
case .main: return "https://api.trustwalletapp.com"
case .classic: return "https://classic.trustwalletapp.com"
case .callisto: return "https://callisto.trustwalletapp.com"
case .poa: return "https://poa.trustwalletapp.com"
case .gochain: return "https://gochain.trustwalletapp.com"
}
}()
return URL(string: urlString)!
}

网络层结构应该如下图所示:

当你明白这种网络结构后, 在来看Trust中, 统一使用xxxRequest的命名来封装JSONRPCKit的应用组件。其中定义了method、parameters、response的转化等, 这里的method就是调用以太坊智能合约的接口名称。项目中, 统一使用xxxProvider的命名, 按功能对APIKit的请求组件进行封装。当然, 没有这层抽象也是可以的。

下面图片中, Trust中涉及到一些 API: eth_estimateGas、eth_sendRawTransaction、eth_gasPrice、eth_blockNumber、eth_getTransactionByHash、eth_call、eth_getBalance。下面详细列出了项目中合约调用的类和具体使用的以太坊 API, 它们是一一对应的关系。

Web3.swift
Trust项目中并没有使用web3的方式进行合约调用, 但是我还是想说一说这种方式。这是因为除了以太坊官方的对 JavaScript API的web3库以外, 还有一个纯Swift写的库Web3.swift。它是可以用于在以太坊网络中签署交易并与智能合约进行交互, 而且可以直接使用于你的iOS客户端。假如你的网络层用Web3.swift替换APIKit + JSONRPCKit这样的话, 将会降低网络层结构复杂度, 且代码简洁性也提高了。

网络层其他请求
在Trust中, 获取区块链上的数据, 其实分为两种, 一种是上面提到的直接通过智能合约获取的数据。另一种就是Trust官网已经封装过的一些接口, 它们是关于多币种的, 大多需要在区块链中去查找, 接口不单一且有大工作量的请求, 如transactions, getTokes等。这些接口是直接使用网络库Moya进行封装的, 而没有调用智能合约。而这些HTTP请求的服务器是:

let trustAPI = URL(string: "https://public.trustwalletapp.com")

TrustAPI类中将这些接口清楚的列举了出来, 并且将它们集体封装在TrustNetwork类中来管理。

到这里, 就将前一篇文章所遗留的网络层的详情补充完整了。

交易
交易, 即Transaction, 我这里是指转账交易。上面简单介绍过以太坊上的交易, 并了解交易的 API是 eth_sendRawTransaction。下面介绍下在项目中, 转账交易的结构, 以及转账交易在原生App和DApp中分别是怎样的流程。

交易的结构
在项目的主目录中, 有一个Transfer模块, 这个模块主要功能就是处理转账交易。在形成一个交易前, 将以定义的Transfer类为基础, 封装出一个Transaction的结构, 这个结构中包含着发送地址、接收地址、币的数量、交易费等等所有交易相关的数据。最后定义TransactionConfigurator类, 对交易进行最外层的业务管理和校验。在TransactionConfigurator中经过校验、签名之后的交易才会发送给以太坊节点, 并在矿工挖到矿并将此交易放入区块中, 当前Token的转账才算完成。

Transfer
Transfer中主要包含当前转账发起方的Token相关的一些数据, 如地址、合约等等。而且它有类型之分, 及TransferType的三种类型, 分别是Coin、ERC20、Dapp, 前两种是原生App的方式, 后一种是浏览器中 DApp的方式。

UnconfirmedTransaction
UnconfirmedTransaction中, 主要包含当前Token的一些信息, 即Transfer。还有一个转账接收方的信息, 如地址、币的数量、交易费、Data等等。

TransactionConfigurator
TransactionConfigurator类, 对交易进行最外层的业务管理和校验。它其中包含全量的UnconfirmedTransaction数据, 且还有校验余额是否有效、交易费、交易限制等功能, 最终生成一个经过校验后的完整SignTransaction。

DappAction
DappAction只在DApp进行转账交易时, 才能使用到的类。而上面的三个无论是原生App还是DApp都需要使用到的交易结构类。DappAction会将浏览器中传入的消息进行解析, 得到Method以及其它数据, 并封装在DappCommand里面。然后以浏览器的web标题和URL生成的DAppRequester等元素生成Transfer。最终这两者, 共同生成的DappAction来决定需要进行哪种操作、需要调用合约中的哪种API、还有交易的一些数据等。

交易结构图

交易的流程
交易流程自然也是分成两, 一种是原生App中发起的交易, 一种是DApp在浏览器中发起的交易。之前提及的交易结构会在流程中以数据的形式作为重要的参与部分, 这里主要说明交易从发起至交易完成的主要流程, 以及需要调用哪些以太坊智能合约的 API。

原生App发起的交易
交易发起。 在原生App的钱包首页有着当前账户下的Token列表, 而发起的转账交易是在某个具体Token中操作的。所以当前的Transfer是已经具备的, 而具体的交易接收地址、币的数量以及gas费就需要用户在SendCoordinator的模块中自行输入了。

构建交易数据。 交易发起后, 我们就具备了构建UnconfirmedTransaction和TransactionConfigurator的所有数据了。它们的具体情况, 前面已经说明过了, 就不赘述了。构建完成TransactionConfigurator后, 进入流程中的ConfirmCoordinator模块, 它的功能是让用户来确认交易详情, 以及核实当前Token的余额是否足够等。

智能合约调用。 当用户确认且余额足够支持转账的情况下, 就需要SendTransactionCoordinator来进行核心的转账交易业务, 所以它是一个纯业务的功能类, 并无页面。这时候要根据在TransactionConfigurator经过校验的 Transaction, 判断其noce是否大于0。如果不大于0, 则需要通过JSON RPC Over HTTP的方式调用以太坊智能合约的API, 即eth_getTransactionByHash对nonce进行更新, 然后重新进行判断; 如果大于0, 则EtherKeystore对交易进行签名, 然后通过JSON RPC Over HTTP的方式调用以太坊智能合约的API, 即eth_sendRawTransaction。

交易回调处理。 交易结果产生后, 要回调至发起的模块, 还要处理后续的业务。如果交易成功, 会将交易保存到本地的Realm数据库等; 如果交易失败, 提示用户交易失败。

到此, 转账交易的流程的闭环完成。在后面的图中也对整个交易流程做了一个梳理。

DApp发起的交易
Trust具有一个功能齐全的Web3浏览器,可与任何分布式的应用程式(DApp)配合使用。这个情景就是当转账交易发生在DApp中发起的情况。交易整体的流程与原生App中基本一致, 且交易的核心数据结构一致。它们的区别在于发起方式、回调处理, 以及DApp中要多一些解析的过程。

交易发起。 在Web3浏览器中的DApp中, 发起转账交易, 发起方式就是JS调用iOS原生。通过传入的数据, 在BrowserCoordinator模块中, 将数据进行解析。

解析。 通过DAppAction、DappCommand、DAppRequester等类进行解析, 完成后, 封装入DAppAction内, 来决定需要进行哪种操作、需要调用合约中的哪种API。它有6种响应事件, 分别是:

1.signMessage
2.signPersonalMessage
3.signTypedMessage
4.signTransaction
5.sendTransaction
6.unknown

构建交易数据 和 智能合约调用。 这两个步骤和原生的之间基本一致, 都是通过数据构建出Transaction, 用来做交易准备。然后进行校验, 再调用智能合约。所以就不具体说明了, 请参照原生App。

交易回调处理。 交易结果产生后, 也要回调至发起的模块, 来处理后续的业务。这里与原生App区别是, 除了需要完成原生App在成功或失败下完成的流程外, 还需要将交易结果再通知到Web, 这样才能形成完整的闭环。所以, 无论回调结果如何, 都会通过iOS原生调用JS的方式通知Web交易的具体情况。

交易流程图

Trust项目到这里基本就很清晰了, 这两篇文章虽然只是对Trust wallet的解读, 很局限。但是由它们能延伸到的知识, 如以太坊的智能合约的知识、钱包和私钥管理的知识等等, 还有你对区块链的认知, 这些不是狭义的。所以无论你认为区块链是好是坏, 或者有没有实际的应用和市场的欢迎, 这门技术都带来了无限创新。

原文地址:https://www.cnblogs.com/nahanzhe/p/10001010.html

时间: 2024-10-12 17:10:49

由Trust Wallet理解以OA信用盘平台出售带杀大赔小功能太坊钱包管理和智能合约的相关文章

C#扩展OA信用盘平台维护的理解

"扩展方法使您能够向现有类型"添加"方法,OA信用盘平台维护(企 娥:217 1793 408)而无需创建新的派生类型.重新编译或以其他方式修改原始类型." 这是msdn上说的,也就是你可以对String,Int,DataRow,DataTable等这些类型的基础上增加一个或多个方法,使用时不需要去修改或编译类型本身的代码. 先做个例子吧,以String为例,需要在字符串类型中加一个从字符串转为数值的功能. 以往我们可能是这样做的,会专门写一个方法做过转换 publ

Typescript 和 Javascript之间OA信用盘平台出租的区别

JavaScript 和 TypeScript 的概要介绍JavaScript 是一种轻量级的解释性脚本语言OA信用盘平台出租QQ2952777280[话仙源码论坛]hxforum.com[木瓜源码论坛]papayabbs.com,可嵌入到 HTML 页面中,在浏览器端执行,能够实现浏览器端丰富的交互功能,为用户带来流畅多样的用户体验. JavaScript 是基于对象和事件驱动的,无需特定的语言环境,只需在支持的浏览器上就能运行. JavaScript 语言具有以下特点: JavaScript

Oracle数据OA信用盘平台出租远程连接的四种设置方法和注意事项

OA信用盘平台出租论坛:haozbbs.com Q1446595067 第一种情况: 若oracle服务器装在本机上,那就不多说了,连接只是用户名和密码的问题了.不过要注意环境变量%ORACLE_HOME%/network/admin/是否设置. 第二种情况: 本机未安装oracle服务器,也未安装oracle客户端.但是安装了pl sql development.toad sql development.sql navigator等管理数据库的工具.在虚拟机或者另一台电脑上安装了oracle服

使用Cmake生成OA信用盘平台出租跨平台项目编译解决方案

项目最近OA信用盘平台出租haozbbs.comQ1446595067 有需求在windows下面运行,我花了几周时间将linux的服务器移植到windows下面,目前已经能够正常运行服务器,目前又有了新需求,两边的代码结构和组织是分开的,因此为了两边能够同步维护,需要一个能够跨平台的项目编译解决方案,经过调研之后,选择了使用cmake这个工具,本文主要讲述,使用cmake的生产项目的一些基础知识.一.cmake简介 你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmak

JDK动态OA信用盘平台出租代理和cglib动态代理

一.代理设计模式OA信用盘平台出租haozbbs.com Q1446595067 代理类和委托类具有相同的接口.代理类的对象本身并不真正实现服务,而是通过委托类的对象的相关方法来提供特定的服务. 二.静态代理 见<大话设计模式>第7章 缺点: 一个代理类只能应用于一个接口的实现类,如果有多个接口的话就要定义很多实现类和代理类才行.而且,如果代理类对业务方法的预处理.调用后操作都是一样的(比如:调用前输出提示.调用后自动关闭连接),则多个代理类就会有很多的重复代码.这时我们可以定义这样一个代理类

Python属性和OA信用盘平台租用

属性有两种,类属性,实例属性.OA信用盘平台租用(企 娥:217 1793 408) 给类下所有的对象添加属性,可以添加类属性,给对象添加的实例属性,类下的其他对象,并不会获得这个属性. class Person(object):pass Person.sex = "male"#所有对象都能获得p1 = Person()p1.age = 12p2 = Person()print(p2.sex)#maleprint(p2.age)#报错AttributeError: 'Person' o

Eureka 2.X 停止开发,但注册中心OA信用盘平台制作还有更多

在上个月我们知道 Eureka 2.X 遇到困难停止OA信用盘平台制作QQ2952777280[话仙源码论坛]hxforum.com[木瓜源码论坛]papayabbs.com开发了,但其实对国内的用户影响甚小,一方面国内大都使用的是 Eureka 1.X 系列,另一方面 Spring Cloud 支持很多服务发现的软件,Eureka 只是其中之一,下面是 Spring Cloud 支持的服务发现软件以及特性对比: Feature euerka Consul zookeeper etcd服务健康检

ArrayList原理、OA信用盘平台出租LinkedList原理和方法和迭代器注意事项

迭代器在变量元素OA信用盘平台出租QQ2952777280[话仙源码论坛]hxforum.com[木瓜源码论坛]papayabbs.com的时候要注意事项: 在迭代器迭代元素 的过程中,不允许使用集合对象改变集合中的元素个数,如果需要添加或者删除只能使用迭代器的方法进行操作. 如果使用过了集合对象改变集合中元素个数那么就会出现ConcurrentModificationException异常. 迭代元素的过程中: 迭代器创建到使用结束的时间. ------意识是迭代器一旦创建,在之后是不可以用集

JS的内置对象之OA信用盘平台维护

charAt()与charCodeAt()OA信用盘平台维护(企 娥:217 1793 408) charCodeAt(index):返回index位置字符的字符编码. charAt():返回index位置的字符本身. var str = "a I love jixi";//charCodeAt() 查找字符编码console.log(str.charCodeAt(0)); // 返回值: 97 ? 根据角标 返回unicode中对应的码表值 //charAt() 查找角标对应值 co