推荐: 精通比特币
比特币原理通俗读本, 比特币:运行原理、典型特性与前景展望
区块链中的公钥地址私钥, 区块链中公钥、私钥、地址之间的关系
比特币官方的开发者文档
区块链中的数据结构
比特币交易中的脚本, 比特币系统的脚本
实践
开源库bitcoinj相关文档, 比特币官网的开发者样例
Bitcoinj 主页:https://bitcoinj.github.io/#introduction
1.1.1 网络参数NetworkParameters
此类用于选择比特币所属网络。
NetworkParameters params; // 网络参数声明 params = TestNet3Params.get(); // 公共测试网络 params = RegTestParams.get(); // 私有测试网络 params = MainNetParams.get(); // 生产网络
1.1.2 Andiod数据存储
简单数据存储: SharePreference
复杂数据存储:sqlite
产生区块链确认个人账户的私钥、公钥、地址。
2.2.1 身份证与地址对应
地址可以与身份信息多对一对应, 在中央数据库落地。
2.2.2 私钥生成算法
bitcoinj实现方案:
ECKey ceKey = new ECKey(); NetworkParameters params = TestNet3Params.get(); ceKey.getPrivKey() // 私钥, BigInteger ceKey.getPrivateKeyAsHex() // 私钥, Hex ceKey.getPrivateKeyAsWiF(params) // 私钥, WIF(Wallet Import Format) ceKey.getPrivKeyBytes() // 私钥 byte[]
2.2.3 公钥生成算法
使用私钥, 通过椭圆曲线算法生成公钥。
bitcoinj实现方案:
ECKey ceKey = new ECKey(); NetworkParameters params = TestNet3Params.get(); ceKey.getPublicKeyAsHex(); // 公钥Hex ceKey.getPubKey() // 公钥原始字节数组byte[]
2.2.4 地址生成算法
Address = RIPEMD160(SHA256(公钥))
bitcoinj实现方案:
ECKey ceKey = new ECKey(); NetworkParameters params = TestNet3Params.get(); ceKey.toAddress(params).toBase58() // base58编码后的地址
使用BitCoinJ的ECKey, Address两个模块。
生成的账户信息(地址,私钥,公钥)使用SharedPreferences存储。
(1)展示用户的当前余额
(2)列出和用户相关的交易明细
3.2.1 UTXO的存储
从网络Node请求存储载有UTXO的Tx, 并存储于本地的SQlite中。
数据表结构[表名tx_utxo]:
Data 二进制数据, output所在的transaction,
index output所在transaction的下表位置。
credit 可信度。 所在区块与尾部的距离。 如果不存在于区块, 值为0。
available 可用金额
hash 交易的hash码, 标识交易
建表语句:
CREATE TABLE IF NOT EXISTS tx_utxo( id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB, credit INTEGER, available INTEGER, hash VARCHAR )
3.2.2 余额计算
分两步实现
(1)向Node请求与UTXOs相关的Tx列表, 并存储于数据库。
(2)获取Tx列表数据, 反序列化, 取得相关UTXO, 将金额相加。
金额从当前账户转到指定账户
4.2.1 生成交易报文。
bitcoinj实现方案:
String ownerPrivInBigIntegerStr = "114975678953706493006078253903895427663346921000308885839647313125562885805365"; BigInteger ownerPrivInBigInteger = new BigInteger(ownerPrivInBigIntegerStr); NetworkParameters params = TestNet3Params.get(); // 构造初始拥有者key ECKey ownerKey = ECKey.fromPrivate(ownerPrivInBigInteger); Address ownerAddress = ownerKey.toAddress(params); Transaction tx = new Transaction(params); Coin initCoin = Coin.valueOf(1000L); tx.addOutput(initCoin, ownerAddress);
tx.bitcoinSerialize()
FileOutputStream fo = new FileOutputStream("d:/tx.data"); tx.bitcoinSerialize(fo); fo.close();
File rf = new File("d:/tx.data"); FileInputStream fis= new FileInputStream(rf); byte[] buf = new byte[1000000]; fis.read(buf); Transaction txx = new Transaction(params, buf);
Coin valueNeeded = Coin.parseCoin("0.09"); // 转账金额 // 转账地址、转账金额 SendRequest request = SendRequest.to(recieverAddress, valueNeeded); request.changeAddress = ownerAddress; ListownerKeys = new ArrayList (); // 设置当前用户的key ownerKeys.add(ownerKey); Wallet wallet = Wallet.fromKeys(params, ownerKeys); WalletTransaction wtx = new WalletTransaction(WalletTransaction.Pool.UNSPENT, unspend); // 将当前用户拥有的utxo所在的交易加入列表 wallet.addWalletTransaction(wtx); // 生成交易 Transaction tx = wallet.sendCoinsOffline(request);
4.2.2 交易合法性验证
// 将交易tx2的某个Trasanction的input与交易tx1相连 tx2.getInput(0).connect(tx1,TransactionInput.ConnectMode.ABORT_ON_CONFLICT); tx2.verify();// 交易的基本数据校验 tx2.getInput(0).verify();// 交易的验签合法
4.2.3 确认交易成功。
交易成功分为以下几个级别。
4.2.4 生成/扫描二维码
转账时需要以二维码的形式呈现地址。使用开源ZXing库实现。
完全参考博文:http://blog.csdn.net/bear_huangzhen/article/details/46053327
4.2.5 数据存储
使用Sqlite存储相关数据
[表名 tx_local]:用户本地发起的交易
_id 自增ID
data 二进制数据,tx序列化数据
credit 可信度。 所在区块与尾部的距离。 如果不存在于区块, 值为0。
amount 交易金额
fee 手续费
hash 交易的hash码, 标识交易
建表语句:
CREATE TABLE IF NOT EXISTS tx_local ( _id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB, credit INTEGER, amount INTEGER, fee INTEGER, hash VARCHAR )
[表名 tx_net]:从网络获取的和用户相关的交易
data 二进制数据
credit 可信度。 所在区块与尾部的距离。 如果不存在于区块, 值为0。