walletnode

package
v2.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2020 License: GPL-3.0 Imports: 24 Imported by: 2

README

Walletnode

Openwallet 基础架构中,生产环境使用 Docker 作为全节点钱包。这将使得重启,备份等操作,都需要实现 “远程”,也就是跨 Docker 容器的调用。

而,大多数开发环境,全节点都是直接安装在本地,这显然和生产环境不一样,那么在同样的代码中,如何使得开发和生产环境适配,是个“问题”。

本节实现基于 Docker 的 Fullnode 管理接口,应用于全节点的:

  • start/stop/restart,重启节点(如导入私钥等)
  • copy/back,远程备份和恢复(如:生产环境中使用docker,而不是本地安装来部署全节点,这时候显然需要跨容器远程复制,而不是本地 cp,因为数据在容器)全节点钱包数据(如:wallet.dat等文件)
  • 兼容本地操作的功能,已开发,待讨论决定

其中 Golang 接口调用示例一:启动,重启,关闭

import "github.com/blocktree/OpenWallet/walletnode"

symbol := "bopo" // 币种,同 assets.Symbo
wn := walletnode.WalletnodeManager{}

// 关闭钱包节点, return error
if err := wn.StopNodeFlow(symbol); err != nil {
    log.Println(err)
}

// 开启钱包节点, return error
if err := wn.StartNodeFlow(symbol); err != nil {
    log.Println(err)
}

// 重启钱包节点, return error
if err := wn.RestartNodeFlow(symbol); err != nil {
    log.Println(err)
}

Golang 接口调用示例二:备份/恢复(only files)

import "github.com/blocktree/OpenWallet/walletnode"

symbol := "bopo"
wn := walletnode.WalletnodeManager{}

// 备份
src := "/data/wallet.dat"  // 备份来源,全节点中的文件 (如: src = MainDataPath + '/' + filename)
dst := "/tmp/2018...../wallet.dat" // 备份目标,自设
if err := wn.CopyFromContainer(symbol, src, dst); err != nil {
    return err
}

// 恢复
src := "/tmp/2018....../wallet.dat"  // 恢复来源,用户提供
dst := "/data/wallet.dat" // 恢复目标的文件名 (如:dst = MainDataPath + '/')
if err := wn.CopyToContainer(symbol, src, dst); err != nil {
    return err
}

使用 wmd node 创建全节点

如果使用 docker+自制镜像 作为钱包节点(无论docker是在本地还是远程),都需要先执行 wmd node create -s Symbol, 否则跳过。过程:

自制镜像

先执行  wmd node create -s Symbol
后执行  wmd wallet create -s Symbol
最后:任何 wmd 命令都可用

wmd node ceate -s Symbol 操作的结果,以 conf/SYMBOL.ini 文件内容的形式输出,这里无专门的 API。

任何对 walletnode 的数据需求,都可以通过此 ini 文件获得(比如 rpcUser/rpcPassword/rpcURL/httpURL 等)

simonluo@MBP15L:mainnet/$ wmd node create -s qtum
2018/09/10 20:18:50 [N] Wallet Manager Load Successfully.
Config file <QTUM.ini> existed!
Init new QTUM wallet fullnode in '/Users/simonluo/.wmd/mainnet/'(
  yes:   to create config file and docker,
  no:    just to create docker,
[yes]: yes                                // 已存在 ini 文件,选择是否重写,否则创建一个新的

Within testnet('testnet','main')[testnet]: main           // 主网/测试链
Where to run Walletnode: local/docker [docker]: docker    // 使用容器/本地安装的方式部署全节点
Docker master server addr [192.168.2.194]: 192.168.2.194  // 如果选择 docker,需提供 master 的 IP 地址
Docker master server port [2375]: 2375                    // Docker 服务端口
Start to create/update config file...
         create success!
         update success!
QTUM walletnode exist: running

simonluo@MBP15L:mainnet/$

如果选择本地安装的全节点(一般用来自己测试或开发)

Within testnet('testnet','main')[testnet]:
Where to run Walletnode: local/docker [docker]: local
Start walletnode command: /usr/local/bin/bitcoin-cli XXXX       // 输入启动命令
Stop walletnode command: /usr/local/bin/bitcoin-cli XXXX stop    // 输入关闭命令
Start to create/update config file...
         create success!
         update success!

Done!

============================================ 以下内容适合深度了解

本接口功能定位

正常情形下,OpenWallet 创建一个币的全节点,含:

  1. 创建节点 wmd node create -s BCH
  2. 创建钱包 wmd wallet create -s BCH
  3. ... 其他业务操作(transfer, backup, restore...)

本接口完成第一步节点管理相关操作,有:

  1. 创建 wmd node create ...
  2. 启动 wmd node start ...
  3. 停止 wmd node stop ...
  4. 重启 wmd node restart ...
  5. 运行状态查看 wmd node status ...

其中创建节点的具体内容,涉:

  1. 创建 conf/SYMBOL.ini 文件 (注意:与 wmd wallet config 协同)
  2. 写入 Walletnode 相关参数 (Walletnode 服务器 类型/地址/文件描述符/前缀...)

本接口的作用

由于 BTC 等钱包中,在恢复钱包,导入私钥等操作中,需要重启节点,所以定义了如下接口来实现节点的操作。

应用中的问题

有两个地方的代码需要升级:

  1. 之前采用指定启动命令方式来重启钱包的,请升级为如下接口来实现
  2. 之前采用本地目录copy方式备份和恢复的,请升级为如下复制接口来实现

其他问题随时 @luo

其他技术细节

  1. 为了兼容开发,测试,生产环境中 walletnode 不同的部署方式,通过 .ini 文件中 ServerType=local/docker 三个参数来指定全节点是 直接安装在裸机或本地PC/安装在本地Docker/安装在远程服务器的Docker。指定后,接口中将自动处理后续问题(连接,pull镜像,创建,备份,恢复等)

  2. 同样,备份也有上述需求(本地的 copy,或 远程的网络传输),通过 WalletnodeManager 这个 Interface 实现几个方法,解决: - 自动选择是从本地还是Docker中备份/恢复文件,避免开发时采用本地 cp,而生产中需要 docker cp(经过 docker 处理备份)的冲突

Documentation

Index

Constants

View Source
const (
	RPCUser       = "walletUser"         //RPC默认的认证账户名
	RPCPassword   = "walletPassword2017" //RPC默认的认证账户密码
	RPCDockerPort = "9360/tcp"           //Docker中默认的RPC端口

	// DockerAllowed = "127.0.0.1" // ?500 For productive environment
	DockerAllowed = "0.0.0.0"

	MainNetDataPath = "/data" //容器中目录,实则在物理机:"/openwallet/<Symbol>/data"
	TestNetDataPath = "/data" //容器中目录,实则在物理机:"/openwallet/<Symbol>/testdata"

	MountSrcPrefix = "/openwallet/data" // The prefix to mounted source directory
	MountDstDir    = "/data"            // Which directory will be mounted in container
)

Variables

View Source
var (
	Symbol                   string                              // Current fullnode wallet's symbol
	FullnodeContainerConfigs map[string]*FullnodeContainerConfig // All configs of fullnode wallet for Docker
	WNConfig                 *WalletnodeConfig
)

Functions

func CheckAndCreateConfig

func CheckAndCreateConfig(symbol string) error

Check <Symbol>.ini file, create new if not

Workflow:

1> 当前目录没有 ini,是否创建?
	1.1 存在,return nil
2> 询问是否设置为测试链?
3> 获取Master服务器IP地址和端口

Types

type FullnodeContainerConfig

type FullnodeContainerConfig struct {
	NAME string
	//CMD      [2][]string // Commands to run fullnode wallet ex: {{"/bin/sh", "mainnet"}, {"/bin/sh", "testnet"}}
	PORT      [][3]string // Which ports need to be mapped, ex: {{innerPort, mainNetPort, testNetPort}, ...}
	APIPORT   []string    // Port of default fullnode API(within container), from PORT
	IMAGE     string      // Image that container run from
	ENCRYPT   []string    // Encrypt wallet fullnode as an option
	STOPCMD   []string    // Use CMD to stop service
	NOTESTNET bool        // Is to support Testnet?
	LOGFIELS  [2]string   // [2]string{mainnet, testnet}
}

type NodeManager

type NodeManager struct {
}

For WMD Interface:NodeManager ()

func (*NodeManager) CreateNodeFlow

func (w *NodeManager) CreateNodeFlow(symbol string) error

Create a new container for wallet fullnode

Workflow:

// 步骤一: 判定本地 .ini 文件是否存在
if  .ini 不存在,创建一个默认的 {
	1> 询问用户配置参数
	2> 创建初始 .ini 文件
} else {									// .ini 存在
	1> 无操作,进入下一步
}

// 步骤二:判断是否需要创建节点容器
if 容器不存在 or 不正常 {
	1> 删除后,或直接创建一个新的(需:)
	2> 导出 container 数据(IP, status)
} else {									// 正常
	1> 导出 container 数据(IP, status)
}

// 步骤三
1> 根据导出的 container 数据,更新配置文件中关于 container 的项(重复更新,方便用户改错后自动恢复)

func (*NodeManager) GetNodeStatus

func (nm *NodeManager) GetNodeStatus(symbol string) error

func (*NodeManager) LogsNodeFlow

func (nm *NodeManager) LogsNodeFlow(symbol string) error

func (*NodeManager) RemoveNodeFlow

func (nm *NodeManager) RemoveNodeFlow(symbol string) error

func (*NodeManager) RestartNodeFlow

func (nm *NodeManager) RestartNodeFlow(symbol string) error

func (*NodeManager) StartNodeFlow

func (nm *NodeManager) StartNodeFlow(symbol string) error

func (*NodeManager) StopNodeFlow

func (nm *NodeManager) StopNodeFlow(symbol string) error

type WalletnodeConfig

type WalletnodeConfig struct {
	RPCUser     string // RPC认证账户名
	RPCPassword string // RPC认证账户密码
	WalletURL   string // Fullnode API URL
	// contains filtered or unexported fields
}

Node setup 节点配置

type WalletnodeManager

type WalletnodeManager struct{}

func (*WalletnodeManager) CheckAdnCreateContainer

func (wn *WalletnodeManager) CheckAdnCreateContainer(symbol string) error

CheckAdnCreateContainer check wallet container, create if not

Pre-requirement

INI file exists!

Workflow:

if 钱包容器存在:
	return nil
else 钱包容器不存在 or 坏了,创建:
	1> 初始化物理服务器目录
	return {IP, Status}

func (*WalletnodeManager) CopyFromContainer

func (w *WalletnodeManager) CopyFromContainer(symbol, src, dst string) error

CopyFromContainer copy file from container to local filesystem

src := "wallet.dat"  // 备份来源,全节点中的�文件名 (MainDataPath + '/' + src)
dst := "2018.....wallet.dat" // 备份目标,自设
src/dst: filename

func (*WalletnodeManager) CopyToContainer

func (w *WalletnodeManager) CopyToContainer(symbol, src, dst string) error

CopyToContainer copy file to container from local filesystem

Define:

src: filename
dst: path

Example:

src := "/tmp/2018......wallet.dat"  // �恢复来源,�用户提供
dst := "wallet.dat" // 恢复目标的文件名 (MainDataPath + '/' + dst)

func (*WalletnodeManager) GetWalletnodeStatus

func (w *WalletnodeManager) GetWalletnodeStatus(symbol string) (status string, err error)

GetWalletnodeStatus get walletnode status

func (*WalletnodeManager) LogsWalletnode

func (w *WalletnodeManager) LogsWalletnode(symbol string) error

LogsWalletnode watch logs now

func (*WalletnodeManager) RemoveWalletnode

func (w *WalletnodeManager) RemoveWalletnode(symbol string) error

RemoveWalletnode remove walletnode

func (*WalletnodeManager) RestartWalletnode

func (w *WalletnodeManager) RestartWalletnode(symbol string) error

RestartWalletnode restart walletnode

func (*WalletnodeManager) StartWalletnode

func (w *WalletnodeManager) StartWalletnode(symbol string) error

StartWalletnode start walletnode

func (*WalletnodeManager) StopWalletnode

func (w *WalletnodeManager) StopWalletnode(symbol string) error

StopWalletnode stop walletnode

type WalletnodeManagerInterface

type WalletnodeManagerInterface interface {
	GetWalletnodeStatus(symbol string) error
	StartWalletnode(symbol string) error
	StopWalletnode(symbol string) error
	RestartWalletnode(symbol string) error

	// 获取全节点配置
	GetWalletnodeConfig(symbol string) *WalletnodeConfig
	// 更新全节点配置
	// UpdateWalletnodeConfig(nc *WalletnodeConfig, symbol string) error
	// 从钱包节点备份到本地
	CopyFromContainer(symbol, src, dst string) error
	// 从本地恢复钱包到节点
	CopyToContainer(symbol, src, dst string)
}

API for Walletnode Management

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL