# BTC RPC节点部署

By [junjie9021.eth](https://paragraph.com/@junjie9021) · 2022-10-22

---

RPC节点参与网络的同步，主要用于查询区块链数据，广播交易等作用；不会参与共识,挖矿。

阅读者建议
=====

*   有一定的linux基础
    
*   熟悉docker
    

安装前置条件
======

*   linux系统
    
*   机器上有docker服务
    

部署脚本
----

Dockerfile

    FROM ubuntu:20.04
    
    ARG VERSION=22.0
    
    RUN apt-get update \
      && apt-get install -y net-tools curl \
      && curl -o /tmp/bitcoin.tar.gz https://bitcoincore.org/bin/bitcoin-core-${VERSION}/bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz \
      && tar -zxvf /tmp/bitcoin.tar.gz -C /opt \
      && mv /opt/bitcoin-* /opt/bitcoin \
      && ln -s /opt/bitcoin/bin/* /usr/local/bin \
      && rm -f /tmp/bitcoin.tar.gz
    
    WORKDIR /btc
    
    EXPOSE 8332
    
    ENTRYPOINT ["sh", "-c", "bitcoind -datadir=/btc -rpcbind=0.0.0.0 -rpcallowip=0.0.0.0/0 -txindex -rpcworkqueue=1000 -rpcuser=$RPC_USER -rpcpassword=$RPC_PWD"]
    

run.sh 脚本

    #!/bin/bash
    
    # 如果需要升级版本，修改这里的版本号后，执行一下run.sh脚本即可。
    VERSION=22.0
    
    docker build --build-arg VERSION=$VERSION -t btc:$VERSION .
    docker stop btc
    docker rm btc
    docker run -d --name btc -p 8332:8332 -v /data/btc:/btc -e RPC_USER="test" -e RPC_PWD="test" --restart=always btc:$VERSION
    

对run.sh赋予执行权限，运行脚本

查看日志

    docker logs -f --tail 20 btc
    

![节点日志,经过一段时间,追赶上最新区块](https://storage.googleapis.com/papyrus_images/f61ec4fcc3cdc021e7f2703401230e5538b79d12f0a64326d3ff85efdd7f5f1d.png)

节点日志,经过一段时间,追赶上最新区块

RPC接口
-----

常用方法:

*   getblockchaininfo 获取最新区块
    
*   getblockhash 获取区块高度hash值
    
*   getblock 获取区块详情
    
*   getrawtransaction 获取交易详情
    

参考文档: BTC官方RPC接口

[https://developer.bitcoin.org/reference/rpc/](https://developer.bitcoin.org/reference/rpc/)

### 获取最新区块高度

    curl -X POST -u test:test -d '{"jsonrpc": "2.0", "method": 
    "getblockchaininfo", "params": [], "id": 1}' http://localhost:8332
    {
      "result": {
        "chain": "main",
        "blocks": 759822,
        "headers": 759822,
        "bestblockhash": "0000000000000000000096b2e9a0db174eeb7a4c15e8a38398593f36032cfb09",
        "difficulty": 35610794164371.65,
        "time": 1666441676,
        "mediantime": 1666438889,
        "verificationprogress": 0.9999988460882687,
        "initialblockdownload": false,
        "chainwork": "000000000000000000000000000000000000000037b5d76943db7b147d7b83e6",
        "size_on_disk": 492851010520,
        "pruned": false,
        "warnings": ""
      },
      "error": null,
      "id": 1
    }
    # "blocks": 759822 此字段为当前区块高度
    

### 获取区块高度的hash值

    curl -X POST -u test:test -d '{"jsonrpc": "2.0", "method": "getblockhash", "params": [759822], "id": 1}' http://localhost:8332 
    {
      "result": "0000000000000000000096b2e9a0db174eeb7a4c15e8a38398593f36032cfb09",
      "error": null,
      "id": 1
    }
    

…

其余接口建议大家自己去尝试

题外话
---

**安全**: RPC节点主要会被Wallet, Dapp, Cex等应用使用。自建RPC节点使用起来也会更安全，放心，不用担心你的请求会被他人拦截导致私密信息的泄漏。

**地址**: 类BTC,ETH的地址都是使用椭圆曲线算法生成，支持离线生成。

### 离线生成地址Python代码样例

    import ecdsa
    import base58
    import hashlib
    import binascii
    
    class Wallet:
        def __init__(self, network='mainnet'):
            # 版本前缀
            self.__pubkey_version_byte = '00' if network == 'mainnet' else '6F'
            self.__wif_version_byte = '80' if network == 'mainnet' else 'ef'
    
        @property
        def pubkey_version_byte(self):
            return self.__pubkey_version_byte
    
        @pubkey_version_byte.setter
        def pubkey_version_byte(self, v):
            if isinstance(v, str):
                raise ValueError
            self.__pubkey_version_byte = v
        
        @property
        def wif_version_byte(self):
            return self.__wif_version_byte
        
        @wif_version_byte.setter
        def wif_version_byte(self, v):
            if isinstance(v, str):
                raise ValueError
            self.__wif_version_byte = v
    
        def __generate_privkey(self):
            privkey = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
            return privkey
    
        def get_pubkey(self, compress=False, privkey=None):
            if not privkey:
                privkey = self.__generate_privkey()
            # 是否压缩，压缩格式的公钥前缀是0x02或0x03，不压缩格式的公钥前缀是0x04
            s = '02' if compress else '04'
            pubkey = s + privkey.get_verifying_key().to_string().hex()
            return pubkey
    
        def get_address(self, pubkey):
            """根据公钥获取地址"""
            # 1.处理传入公钥格式
            sha256Key = hashlib.sha256(binascii.unhexlify(pubkey)).hexdigest()
            ridemp160FromHash256 = hashlib.new('ripemd160', binascii.unhexlify(pubkey))
            # 2.将 00 作为网络字节添加ripemd160公钥
            prepend_network_byte = self.__pubkey_version_byte + ridemp160FromHash256.hexdigest()
            # 3.将双重 SHA256 应用于prepend_network_byte以校验和
            hash = prepend_network_byte
            for x in range(1,3):
                hash = hashlib.sha256(binascii.unhexlify(hash)).hexdigest()
            checksum = hash[:8]
            # 4.附加值
            append_checksum = prepend_network_byte + checksum
            # 5.base58编码
            address = base58.b58encode(binascii.unhexlify(append_checksum))
            return address.decode('utf8')
    
        def generate(self):
            """生成地址"""
            privkey = self.__generate_privkey()
            pubkey = self.get_pubkey(privkey)
            address = self.get_address(pubkey)
            self.privkey = privkey.to_string().hex()
            self.pubkey = pubkey
            self.address = address
            return address
    
        def privkey_to_wif(self, privkey):
            """私钥格式转钱包导入格式"""
            prepend_network_byte = self.__wif_version_byte + privkey
            hash = prepend_network_byte
            for x in range(1,3):
                hash = hashlib.sha256(binascii.unhexlify(hash)).hexdigest()
            checksum = hash[:8]
            append_checksum = prepend_network_byte + checksum
            privkey = base58.b58encode(binascii.unhexlify(append_checksum))
            return privkey.decode('utf8')
    
    if __name__ == '__main__':
        wallet = Wallet()
        wallet.generate()
        print(wallet.address, wallet.privkey)

---

*Originally published on [junjie9021.eth](https://paragraph.com/@junjie9021/btc-rpc)*
