【p2p、分布式,区块链笔记 Blockchain】OP_RETURN 比特币数据存储操作

OP_RETURN操作

OP_RETURN 的优缺点

  • 空间有限: OP_RETURN不适合存储大规模数据。最初,OP_RETURN 只能允许嵌入 40 字节 的数据,限制了用户可以存储的信息量。后来,随着 Bitcoin Core v0.11 的发布,OP_RETURN 的数据限制从 40 字节增加到了 80 字节,使得可以存储更多的元数据。

  • 无法花费的输出:该脚本将交易输出存储在未花费交易输出 (UTXO) 集中。每次使用 OP_RETURN 操作码都会导致相应的比特币无法被花费,这在大量使用时可能会浪费比特币。

OP_RETURN 的常见用途

  1. 记录数据:通过 OP_RETURN,可以将任何信息存储到区块链上,比如证明、所有权声明、身份认证、用户名注册等。

  2. 时间戳服务:通过将特定数据(如文件的哈希值)嵌入到区块链交易中,用户可以证明该数据在某一时间点之前存在。这通常被称为区块链时间戳服务。

  3. 资产发行:许多基于比特币的项目使用 OP_RETURN 来实现代币或其他资产的发行,比如 Omni Layer 和 Counterparty。通过这种方式,用户可以通过比特币网络追踪和转移其他类型的资产。

  4. 智能合约:尽管比特币的脚本语言并不具备以太坊那样复杂的智能合约功能,但简单的合约逻辑仍然可以通过 OP_RETURN 实现。OP_RETURN 还可以用来标记和触发外部应用程序的事件。

Blockname 项目

  • Blockname 项目是使用区块链注册域名(node bin/register.js "somename.tld" 12.34.56.78)。项目使用raw-op-return (“git+https://github.com/quartzjer/raw-op-return.git”),专门用于比特币中的OP_RETURN操作码。它允许在比特币交易中嵌入任意数据,常用于创建不可变的链上记录。依赖是通过GitHub的链接直接引用的。
// 引入必要的库
var bitcoin = require('bitcoinjs-lib');  // 用于创建和处理比特币交易的库
var opret = require('raw-op-return');  // 处理比特币的OP_RETURN输出,允许嵌入任意数据
var ip = require('ip');  // 处理IP地址的库
var level = require('level-party');  // 允许多个进程共享同一LevelDB数据库的库

// 配置命令行参数解析
var yargs = require('yargs')
  .describe('db', '提示存储数据库的目录')  // 说明'db'参数用于指定数据库目录
  .describe('key', 'WIF格式的私钥,用于注册交易')  // 说明'key'参数用于提供私钥
  .boolean('test')  // 定义'test'参数为布尔值
  .describe('test', '使用测试网水龙头为注册提供资金')  // 说明'test'参数用于测试网
  .default('test', true)  // 设置默认值为'true',使用测试网
  .usage('Usage: $0 "domain" 1.2.3.4:5678 [satoshis] [refundto]')  // 提供命令行工具的用法说明
  .demand(2);  // 要求至少提供2个参数
var argv = yargs.argv;  // 解析命令行参数

// 获取并解析命令行输入的域名和IP地址
var domain = argv._[0];  // 获取第一个位置参数,域名
var ipp = argv._[1].split(':');  // 获取第二个位置参数,IP:端口对
try {
    
     var server = ip.toBuffer(ipp[0]); } catch(E) {
    
    }  // 将IP地址转换为Buffer对象,便于比特币交易处理
if(!server || server.length != 4) return console.error('错误的IP地址',argv._[1]);  // 验证IP地址是否有效

// 检查是否指定了端口,注册NS提示
if(ipp.length > 1) {
    
    
  var port = parseInt(ipp[1]) || 53;  // 获取端口号,默认为53(DNS端口)
  var ns = new Buffer(2);  // 创建2字节的缓冲区存储端口号
  ns.writeUInt16BE(port,0);  // 将端口号写入缓冲区
  var hint = '*.' + domain + server.toString('hex') + ns.toString('hex');  // 构建带有端口号的NS提示
} else {
    
    
  var hint = '*!' + domain + server.toString('hex');  // 构建不带端口号的提示
}

// 如果提示太大,输出错误信息
if(hint.length > 40) return console.error('提示太长,名称必须小于32个字符:', hint);

// 设置比特币网络:根据test参数选择测试网或主网
var network = argv.test ? bitcoin.networks.testnet : bitcoin.networks.bitcoin;
var key = argv.key ? bitcoin.ECKey.fromWIF(argv.key) : bitcoin.ECKey.makeRandom();  // 使用提供的私钥,或者生成一个新的私钥
var address = key.pub.getAddress(network).toString();  // 从私钥生成比特币地址
var dbdir = argv.db || (__dirname + '/db');  // 设置数据库目录
var db = level(dbdir, {
    
     encoding: 'json' });  // 打开数据库,使用JSON编码
var helloblock = require('helloblock-js')({
    
    network:argv.test?'testnet':'mainnet'});  // 设置helloblock-js,指定使用测试网或主网

// 可选的花费用于注册
var value = parseInt(argv._[2]) || 1000;  // 默认注册花费为1000聪
var refund = argv._[3] || address;  // 如果没有指定退款地址,默认使用生成的地址

// 输出一些调试信息
console.log('使用私钥 (WIF)', key.toWIF(), argv.test);
console.log('公钥地址 (需要资金)', address);
console.log('注册提示 `%s` 到 %s (OP_RETURN `%s`)', domain, ip.toString(server), hint);
console.log('花费 %d 并将余额返还到 %s', value, refund);

// 如果是测试模式,使用测试网水龙头获取资金
if(argv.test) {
    
    
  helloblock.faucet.withdraw(address, 10000, function(err, res, ret) {
    
    
    if(err) return console.error('faucet withdrawl failed', err);
    unspent();  // 成功获取资金后,继续寻找未花费输出
  });
} else {
    
    
  // 实时模式,开始查找未花费的输出
  unspent();
}

// 不断查找地址的未花费输出,直到找到足够的资金
function unspent() {
    
    
  helloblock.addresses.getUnspents(address, function(err, res, unspents) {
    
    
    if(err) return console.error('fetching unspent failed', err);
    var total = 0;
    unspents.forEach(function(utx) {
    
    
      total += utx.value;  // 累加所有未花费输出的金额
    });
    if(total < value) {
    
    
      console.log('not enough funds found yet, waiting...', total, value);
      return setTimeout(unspent, 10*1000);  // 如果资金不足,等待10秒后重试
    }
    register(key, refund, unspents, hint);  // 如果资金足够,执行注册
  });
}

// 执行注册交易
function register(from, to, sources, hint) {
    
    
  console.log('执行注册');

  // 签署交易
  var signTransaction = function(tx, callback) {
    
    
    tx.sign(0, from);  // 使用提供的密钥签署交易的第一个输入
    callback(false, tx);
  };

  // 传播交易到比特币网络
  var propagateTransaction = function(tx, callback) {
    
    
    helloblock.transactions.propagate(tx, function(err, res, body) {
    
    
      callback(err, res);  // 传播完成后调用回调
    });
  };

  // 使用OP_RETURN模块
  opret.post({
    
    
    stringData: hint,  // 注册的提示数据
    address: to,  // 目标地址
    fee: network.estimateFee,  // 估计手续费
    unspentOutputs: sources,  // 使用的未花费输出
    propagateTransaction: propagateTransaction,  // 传播交易的回调函数
    signTransaction: signTransaction  // 签署交易的回调函数
  }, function(error, postedTx) {
    
    
    if(error) return console.error('注册错误', error);
    console.log('已注册提示', postedTx.txHash);  // 输出交易哈希
    db.put(domain, {
    
    ip:ip.toString(server),v:postedTx.totalInputsValue}, function() {
    
    
      process.exit();  // 将注册信息保存到数据库后退出程序
    });
  });
}

CG

猜你喜欢

转载自blog.csdn.net/ResumeProject/article/details/143029006
今日推荐