面試補充

覺得在每一份工作都得到讓我成長的養分
希望有機會能夠加入貴公司的團隊
能夠學習到更多新知和精進各種技能

自我介紹

  • 擁有資深的golang語言開發經驗 (8年)

  • 曾參予交易所 和 捕魚和棋牌類 相關遊戲等大型微服務架構設計

  • 擅長 棋牌類,SLOT 捕魚機 遊戲開發 ( 熟悉鬥地主AI模型 )

  • 擅長開發捕魚遊戲機率 (撰寫核心機率, 反覆大數據測試驗證RTP )

  • 有獨立開發 登入Server和 遊戲Server 實務經驗, 可橫向擴充, 且有上市場驗證 server架構圖

  • 熟系高併發大型微服務系統架構

  • 熟悉 mysql redis rabbitmq, kafka mongodb

  • 會使用 docker-compose 搭建各種服務

  • 將程式專案寫 dockerfile, docker build image 丟到 dockerhub 或自己架設的私有倉庫

  • 使用 gin 或 websocket gorilla 來開發微服務

  • 交易所 1年 實務經驗

  • 會區塊鍊錢包 bitcoin eth(erc20), 也會自架節點 (獲取區塊鍊高度 打包交易上傳到鏈上, 持續監聽區塊確認高度, 完成此交易)

  • 目前在研習智能合約開發 [發佈時的已部署的合約](
    0xbb6fB7B6Ca2A864776d4eaD564B7Ba98c1AaBABf

關於CI/CD 這塊

  • 會使用 docker-compose 搭建各類linux服務
  • 會針對程式專案寫DockerFile 將 image 上傳到 dockerhub 或 自建私有倉庫
  • 會搭建 jenkin 並且 寫 腳本 來 佈署 微服務
  • 專案導入docker, 打包docker image 上傳到dockerhub或自建的harbor倉庫
  • 基本GCP搭建VM和相關服務設定

記憶體狀態管理, channel, goroutine, 及這些東西常用的應用情境.

線上範例
websocket + channel 應用範例
持續優化的DDD微服務
erc20錢包

  • 底層框架使用 gorilla
  • 每個 websocket session 都配置 讀寫通道buffer, buffer大小為100, 來依序接收和依序傳送數據
  • 將接收到的訊息塞入 channel(job queue)
  • 收到 channel 資料後, 解析 封包資料, 依序執行封包的 cmd 命令
  • 收到 close_server 封包後, 會透過通道關閉此 websocket連線資源
  • 每個 登入的 user, 都配置 100個通道buffer, 用在跟平台錢包溝通(儲幣,提幣,餘額請求)
  • 主要是在鈊象電子學習了 client繪圖引擎底層 和 tcp協定的 client和server框架
  • 在永勝雲端 有了獨自開發一整套 可橫向擴充 game_server 架構的 機會 [理想的server架構圖](理想的server架構圖
  • 在新禾學習了 GRPC 和 stored procedure, 也學習了其他大師設計的 server 架構
  • 在亞太滿譽 學習了 區塊鍊節點架設 區塊鍊錢包API溝通相關 智能合約撰寫和使用, 還有各種 docker-compose 啟動的服務架設
  • 自我學習 dockerfile 和 打包image

關於map

種類 說明 支援多執行序
map 一般的map 否, 在goroutine直接引用map, 會引發panic, 需搭配鎖來使用
sync.map 支援goroutine安全的map 是, 但因為頻繁的鎖, 效能會低落, 適用於讀多寫少的場景。對於寫多的場景, 還是要使用一般map+鎖

關於mutex

說明 效能
sync.Mutex 一般互斥鎖 性能較差, 因為 針對 大量變數讀取時的鎖, 會瞬間阻塞一下
sync.RWMutex 讀寫互斥鎖 性能較好, 因為 針對 大量變數讀取時的鎖, 彼此讀鎖不會阻塞, 但寫鎖lock時, 讀寫鎖都阻塞等待寫鎖unlock, 可以用在 讀取用戶排行榜或配桌列表

sync.RWMutex 針對鎖的操作有更細部的控制
針對讀多寫較少的場景, 可以大幅度的提升效能

讀寫鎖範例

// 使用讀鎖 加快效能 func (mgr *TableManager) GetTableList() []*Table { mgr.EGMLocker.RLock() defer mgr.EGMLocker.RUnlock() // 讀取配桌列表 (因為是讀鎖, 所以不會阻塞, 可以讓多人同時讀取 配桌列表 return mgr.ListTableMap } // 使用寫鎖, 阻塞其他鎖 func (mgr *TableManager) SetId( userId int, data string) { mgr.EGMLocker.Lock() defer mgr.EGMLocker.Unlock() // 因為是寫鎖, 所以這邊同一時間只有一個 goroutine能夠使用此變數, 其他晚來的會阻塞等待(讀寫都會阻塞等這邊完成) mgr.ListTableMap[userId] = data }

由於 頻繁鎖還是會造成效能低落, 還有不易維護的問題
所以如果是有順序的工作, 可以使用 channel 來達成
優點是

  • 效能提升
  • 容易維護
  • 在整個關鍵的地方上鎖, 鎖的數量變少, 不容易造成死鎖

例如 websocket gorilla 就是一個好例子

每個websocket client 都配置 一個 讀取和寫入 chan buffer 來依序 接收或傳送 資料並處理

細節參考剛寫的 websocket + channel 應用範例

websocket 針對每個 客戶端 session 物件初始化時, 分別建立一個讀寫通道 s.writeChan = make(chan []byte, 1000) s.readChan = make(chan []byte, 1000) // 將要返回給client的資料塞入通道 func (s *Session) Send(data []byte) { s.writeChan <- data } func (s *Session) Run() { for { select { case <-s.exitChan: // 收到離開的訊號 return case sendData := <-s.writeChan: // 通道收到資料後, 寫到 websocket底層送出 err := s.ws.WriteMessage(websocket.TextMessage, sendData) if err != nil { log.Println("websocket send message error", err) } } } }

對於架構面, 例如 queue, cache, db, 實作層面和適用情境.

redis 常用資料結構

資料結構 內容
string 單一的快取結果,不與其他的Key Value 之間有聯繫 ( 當成map結構使用 )
hash 一個Object 包含有許多屬性,而這些屬性都需要單獨儲存 ( 例如儲存登入 user )
list 一個Object 包含很多數據,且這些數據允許重複、要求有順序性 (例如工作queue)
set 一個Object 包含很多數據,不要求數據有順序,但是不允許重複
zset 一個Object 包含很多數據,而這些數據本身還包含一個權重值,可以利用這個權重值來排序

queue 主要用在需要順序執行的工作
例如跟第三方錢包的 提幣/充值/取得餘額, 可以使用下列方式來達成 job queue

  • 使用 channel buffer 來達成 依序處理錢包
  • 使用 rabbitMq 來達成 例如 login_server -> MQ > money_server > 第三方wallet
  • 使用 redis 的 list

image

使用 cmd 來示範 list 當作 queue ( lpush rpop )
image

redis 拿來當緩存cache 是目前主流的方式
除了可以讓每隻server都可以達到無狀態, 方便日後打包成docker image, 推進到k8s上

# 將登入的user 寫入到 new_user 資料夾內 key = new_user:userId hset new_user:123 data '{ "token": "aaaa", "userId": 123 }' # 設定倒數秒數, 時間到自動銷毀 EXPIRE new_user:123 180

image

redis 的 pub 和 sub 適合用來 廣播某人中JP的通知, 但因為會漏失, 所以適合廣播不重要的訊息

redis 的分佈式鎖, 可以用來避免 redis 上的資料競爭
常見的舊方式可以使用 setnx + expire 兩個指令來上鎖, 但分兩個指令, 如果中間panic就死鎖 ( 未來官方可能會拋棄相關語法 )
刪除鎖就 del

新版redis 官方建議方式是使用 set NX EX 指令
假設 ttl=30秒, 用set指令來取代 setnx
set key value ex 30 nx

set key value ex 30

set key value ex 30 nx = setnx + expire

都有不同效果

分布式鎖使用範例
key = lock, value = 自產唯一uuid, ttl = 30s

  • set lock uuid ex 30 nx
  • 檢查回傳值是否為ok, 如果ok代表可以去存取 redis共享變數, 如果是null, 代表有人正在使用共享資源 請稍後在測試
  • 存取redis共享變數
  • 在30s之前使用完畢的話, 要 delete lock 把鎖給手動釋放

深度剖析:Redis分散式鎖到底安全嗎?

高併發 高可用的redis

redis三種模式

  • 主從模式 主(master)掛了 需要手動去切換到從(slave)
    image

    • 優點
    • 架設簡單
    • 一個是讀寫分離,分擔 "master" 的讀寫壓力
    • 一個是方便做災難復原
    • 資料可靠性提升
    • 缺點
    • 不具備自動容錯和復原功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或手動切換前端的IP才能恢復(也就是要人工介入)
    • 較難支援線上擴容,在叢集容量達到上限時線上擴容會變得很複雜
    • 浪費空間, 同樣的資料儲存在多個slave內
  • 哨兵模式 一個哨兵監控多個Redis 實例, 故障偵測 通知 故障轉移
    image

    • 優點
    • 哨兵模式是繼承主從模式的,所有主從的優點,哨兵模式都具有。
    • 主從可以自動切換,系統更健壯,可用性更高(可以看作自動版的主從複製)。
    • 缺點
    • 每台Redis 伺服器都儲存相同的數據,很浪費內存。
    • Redis較難支援線上擴容,在叢集容量達到上限時線上擴容會變得很複雜。
  • 從集模式 分散式儲存資料, 同樣的資料分布在不同的redis
    image

    • 優點
    • 可以横向擴充, 只需連接集中某幾個節點即可
    • 利用CRC16演算法, 將資料平均分散在16384哈希槽,保有資料的分散性
    • 公式 HASH_SLOT = CRC16(key) / 16384
    • 缺點
    • 維護較困難
    • 某些指令因為跨槽問題, 所以不支援

redis cluster 利用crc16演算法將資料分散在不同實體
image

redis優化方向

  • 開啟慢查詢log
  • 設定 ttl ( 但不可以過度集中的釋放大量的key )
  • 少用複雜或排序的指令, 運算類拉回微服務內 ( set, zadd, keys )
  • bigkey ( value 容量別太大 )
  • AOF 策略設定錯誤 ( 自己覺得最好是 appendfsync everysec:主執行緒每次寫入操作只寫記憶體就返回,然後由後台執行緒每隔1 秒執行一次刷盤操作(觸發fsync系統呼叫),此方案對效能影響相對較小,但當Redis 宕機時會遺失1 秒的數據)

Redis進階- 效能調優
Redis 數據持久化機制、主從同步原理、常見規範與優化詳解

自己過往的經驗與知識整理出一些現有痛點的解決方案

永勝雲端任職
是我第一次獨立製作專案的時機
因為剛到台中的新創公司
我是第一批入職的員工
在了解業務的需求後
也跟老闆提供的技術顧問討論後
製作了一款 可以簡易橫向擴充的捕魚機和SLOT的遊戲架構原型

整個系統我主要撰寫了90%左右的代碼, 剩下的部分是後進同事協助完成

因為當年golang在台中不好招募, 後來只補了兩位golang工程師

104上的遊戲demo

理想的server架構圖

photo_2024-12-27 14.40.21

設計理念就是

  • 利用 proxy 來阻擋dot惡意攻擊, dot時, 不斷水平擴充proxy, 可以簡單減輕此區壓力
  • proxy 主要來做資料轉拋層, 將不同api請求, 轉交給處理的微服務
  • 根據不同需求, 建設不同的微服務
  • 利用 redis cluster 來存取運行的快取資料
  • 微服務的熱資料都儲存在 redis上, 日後要橫向擴充時會比較好擴充
  • 微服務的重要數據儲存在db, 當有用戶來存取時, 先去redis撈取, 如果沒有再去db找, 最後在更新回redis上
  • 如果有重要的工作可以提交給 message queue, 來達到 封包資料可靠送到, 資料依序排列處理 的優勢
  • 大量的微服務產生的log 可以寫入 mongoDB, 再透過GUI介面來撈取不同等級的log訊息
  • 資料庫使用 讀寫分離 都對master做寫入, 讀取資料
  • 後台報表都對 slave 做讀取

之前壓測過程中發現一些問題

musql的index有漏加

利用 explain 來找出那些 sql 語法需要增加 index
image.png

SELECT * FROM orders WHERE user_id = ? AND status = ? AND created_at >= ?
index A : idx_user_id_status_created_at(user_id, status, created_at)

索引的細節
image
explain的結果
image

聯合索引的規則是
先將聯合索引 最左邊 的開始排序
在第一個欄位的排序基礎下, 在使用第二個欄位進行排序
而且索引不能夠跳著 例如 1 3

可以用 explain 來 交叉比對誰的效能較高

key_len決定了索引項目在儲存空間佔用的大小,越小意味著一個磁碟區能夠放置的索引項越多,
從而可以降低B+樹的高度,高度低就意味著查找時所搜尋的路徑越少,
例如一個三層B+樹,從根到葉節點只需2步,而四層就需要3步了,
而搜尋的路徑少就意味著磁碟IO讀取次數少(如果沒有全放內存的話),自然就提高查詢的效率了

type類型從快到慢:system > const > eq_ref >ref >range > index > ALL

type 說明
system 系統表,少量數據,往往不需要進行磁碟IO
const 常數連接
eq_ref 主鍵索引(primary key)或非空唯一索引(unique not null)等值掃描
ref 非主鍵非唯一索引等值掃描
range 範圍掃描
index 索引樹掃描
ALL 全表掃描(full table scan)

explain

mysql慢查詢要打開
show variables like 'slow%';
set global slow_query_log = on;

# 開啟慢查詢 slow_query_log = 1 long_query_time = 10 slow_query_log_file =/usr/local/mysql/mysql_slow.log

開啟效能詳情
show variables like '%profiling%';
set profiling = on;
show profiles;

mysql的buff要優化 my.cnf

[mysqld] datadir=C:/Program Files/MariaDB 10.3/data port=3306 # 不可過大(約服務器物理內存大小的80%) #innodb_buffer_pool_size=2020M innodb_buffer_pool_size=5G character-set-server=utf8 max_connections=10000 #column-statistics=0 key_buffer= 4096M bulk_insert_buffer_size = 1G # 查詢緩衝 query_cache_size = 32M # 允許進入查詢緩衝區的最小數據大小 query_cache_limit = 512M # Thread cache的作用在於每次建立新的連線 (Thread) 時,會先看Thread cache 中是否有可用的 Thread,若有則直接取用,若無才重新建立新的連線 thread_cache_size = 8 innodb_flush_log_at_trx_commit=0 innodb_lock_wait_timeout = 100 ###### # 為InnoDB資料表及其索引而保留的RAM記憶體量(默認設置是8MB)。這個參數對速度有著相當大的影響,如果計算機上只運行有MySQL/InnoDB資料庫服務器,就應該把全部記憶體的80%用於這個用途。 #innodb_log_buffer_pool_size = 32M # 開了跑不起來 #innodb_log_file_size = 256M # 事務日誌文件寫操作緩存區的最大長度(默認設置是1MB) innodb_log_buffer_size=16M #innodb_log_files_in_group=3 # 禁止autocommit init_connect='SET autocommit=0' # InnoDB驅動程序能夠同時使用的最大線程個數(默認設置是8)。 #innodb_file_io_threads=8 # InnoDB驅動程序能夠同時使用的最大線程個數(默認設置是8)。 innodb_thread_concurrency=256 # 帶有autoextend屬性的表空間文件每次加大多少兆字節(默認設置是8MB) innodb_autoextend_increment=64M innodb_concurrency_tickets=5000 innodb_old_blocks_time=1000 # innodb_open_files=1000 innodb_stats_on_metadata=0 # innodb_file_per_table=1 #innodb_checksum_algorithm=0 max_connect_errors = 4294967295 #max_allowed_packet = 10M #Net_buffer_length = 32768 query_cache_type = 1 open_files_limit = 1024 read_buffer_size = 131072 # 修改資料插入上限 ( insert 或 update 資料上限 ) 預設值是 16MB max_allowed_packet = 1G thread_stack = 192K thread_cache_size = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover = BACKUP max_connections = 10000 query_cache_limit = 512M query_cache_size = 32M expire_logs_days = 10 max_binlog_size = 100M [client] port=3306 plugin-dir=C:/Program Files/MariaDB 10.3/lib/plugin

因為使用到 mysql 批次寫入功能 ( 開個 goroutine, 蒐集等待寫入的注單資料, 蒐集約1000筆就整批寫入到sql)

批次寫入sql語法

INSERT INTO table_name (column_list) VALUES (value_list_1), (value_list_2), ... (value_list_n);

除了基本的buffer條大外, 以下參數需要特別調整

  • max_allowed_packet
  • bulk_insert_buffer_size 大量插入批次緩存
  • innodb_flush_log_at_trx_commit
  • SET autocommit=0 禁止auto commit

利用mysql workbench工具來監測效能
mysql workbench 的 dashborad 面板 裡面有目前sql操作的相關數據
可以用來分析目前批次寫入的狀態
image

linux上的調整
sudo vim /etc/security/limits.conf

* soft nofile 10240 * hard nofile 10240

高併發的mysql

利用主從分離來達到讀寫分離, INSERT 再寫的連線上, 大量的查詢在讀的連線上
應用例子是
前台使用 master連線在寫入
後台使用 slave 連現在讀取

利用 分table表功能
image

適度的分庫和分表


clean code

  • 適當有意義的命名

  • 函式一次只做一件事, 且沒有副作用



區塊鏈筆記

自己整理的區塊鏈知識

BTC節點架設

btc 鏈幣種功能

DOC

RPC API Reference
比特币 RPC API 目录
Bitcoin Transactions
how to send raw transaction BTC using Bitcoin-cli command
create-bitcoin-address-from-ecdsa-publickey
三种比特币地址格式

第三方付費節點-getblock

測試鏈
blockstream testnet

fee 手續費過低 會提幣失敗

fee: 0.000002
fee_ok: 0.00000141 <=== 比他低就容易失敗
fee_fail: 0.00000002

一般指令

啟動 / 關閉節點

啟動, default_port=18332
bitcoind -testnet -conf=/data/btc_data/bitcoin.conf -daemon

關閉
bitcoin-cli -testnet -rpcuser=bitcoinrpc -rpcpassword=btc2018 stop

創建錢包

bitcoin-cli -testnet -conf=/data/btc_data/bitcoin.conf createwallet "testwallet" 如果沒創建錢包, getnewaddress 會得到 get center address err:record not found **重新加載錢包** bitcoin-cli -testnet -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 loadwallet testwallet bitcoin-cli -testnet -rpcuser=bitcoinrpc -rpcpassword=btc2018 loadwallet testwallet **列出所有錢包** bitcoin-cli -testnet -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 listwallets

創建用戶錢包地址

bitcoin-cli -testnet -rpcuser=bitcoinrpc -rpcpassword=btc2018 getnewaddress

回傳 用戶錢包地址

tb1q83yazmfte7w3fv64eaqqjv2rmnj3agsy6c3zh4

導出錢包私鑰

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "dumpprivkey", "params": ["tb1q83yazmfte7w3fv64eaqqjv2rmnj3agsy6c3zh4"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

回傳錢包私鑰

{"result":"cUz5KrxVm93Uz1t939A9jyegXu2RggbePfUAgMvnyimmnJwSFtX1","error":null,"id":"testwallet"}

獲取目前最新高度

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockcount", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

結果 result=測試鏈區塊高度

{"result":2540747,"error":null,"id":"curltest"}

獲取目前區塊資訊

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblockhash", "params": [2428582]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

回應 區塊的hash

{"result":"00000000000000167198a12e7941e653dd9151fdb941624a386c5ffff699554a","error":null,"id":"curltest"}

獲取目前區塊內的交易明細

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getblock", "params": ["00000000000000167198a12e7941e653dd9151fdb941624a386c5ffff699554a"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

列出整個區塊內包含的交易資訊
2428582區塊的查詢結果

獲取 txhash 的交易明細

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "gettransaction", "params": ["bd505fe95841ceec254008a6c86e25cb79a69043855747b4f63bb0a85bcc7b54"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

tx 內 一堆交易的 txId
image

獲取 txhash 的交易明細(raw data)

curl --user bitcoinrpc:btc2018 --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getrawtransaction", "params": ["bd505fe95841ceec254008a6c86e25cb79a69043855747b4f63bb0a85bcc7b54"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

查詢結果

{"result":"02000000000101e21b02768d9b3081a131db1664dee3e977ed569e88b074ca0191659ed08e137a0000000000feffffff02fefb1100000000001600143da33c22bf1ad527ac92605c1f179a326f8c17e01e150000000000001600142a7421b6ed38c5c3618ac8d33983b425ab0ba3820247304402207fbc7ad987b197be2e51512c0d909401402a2e659f08b91a5e2bf4c2585fba0002205927c61e22d6d5ec12607b1c8c1e813a0d0b90fe0b2c0a362be3be41fd5f4355012103451b939ab892542e0d15cc17f205a4c87255b79f442a154d776701633a090491f10d2500","error":null,"id":"curltest"}

raw data內的資訊

交易指令 1

Here's how to send raw transaction BTC using Bitcoin-cli command

範例的資料
來源地址資料
address tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e
secret_key cR7zWWke3wEVnCsP9NHAB6uFt8Lmi7DKGceohGXPbJUiTT7hg8zd

目的地址
address tb1q2tl7ze6dxc8p8pqx2jwjazw86n4fyfvxr3rwqu

先到水龍頭去充值
https://bitcoinfaucet.uo1.net/

導出私鑰
curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "dumpprivkey", "params": ["tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

結果
{"result":"cR7zWWke3wEVnCsP9NHAB6uFt8Lmi7DKGceohGXPbJUiTT7hg8zd","error":null,"id":"curltest"}

列出所有未花费
curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "listunspent", "params": [0, 9999999, ["tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e"] , true ]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

結果
{"result":[{"txid":"511671b1ed7ed89fe46ba99de3290b832f2c9da11d0a3972a674ddc2391a2b0c","vout":2,"address":"tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e","label":"","scriptPubKey":"001422da97b29bbb5d5de50d5b8ed632374f51811352","amount":0.00005344,"confirmations":52,"spendable":true,"solvable":true,"desc":"wpkh([0ea36790/0'/0'/71']02f89309da92f327e9e8b547f72b9563deaee2deef9bfc2803991df4dd48d67cdd)#durvzft4","safe":true}],"error":null,"id":"testwallet"}

目前此錢包帳戶餘額
amount = 0.00005344

創建原始交易
參數 1 要交易的小錢包 txid, vout 要 跟 listunspent 一樣
參數 2 目的地址和收到的金額, 來源地址和此小錢包最後餘額
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 createrawtransaction "[{"txid":"511671b1ed7ed89fe46ba99de3290b832f2c9da11d0a3972a674ddc2391a2b0c","vout":2}]" "[{"tb1q2tl7ze6dxc8p8pqx2jwjazw86n4fyfvxr3rwqu":0.00001},{"tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e":0.00004144}]"

來源地址原始金額 - 想提幣的金額 - 手續費 = 來源地址最後餘額
0.00005344 - 0.00001 - 0.000002 = 0.00004144

計算第一筆
0.01145407 => 0.00006 + 0.01133891 + 0.00005344

0.01145407 - 0.01145235

結果 拿到 hexstring
02000000010c2b1a39c2dd74a672390a1da19d2c2f830b29e39da96be49fd87eedb17116510200000000ffffffff02e80300000000000016001452ffe1674d360e138406549d2e89c7d4ea922586301000000000000016001422da97b29bbb5d5de50d5b8ed632374f5181135200000000

用私鑰簽署原始交易
參數 1 上一個步驟的 hexstring
參數 2 私鑰
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 signrawtransactionwithkey "02000000010c2b1a39c2dd74a672390a1da19d2c2f830b29e39da96be49fd87eedb17116510200000000ffffffff02e80300000000000016001452ffe1674d360e138406549d2e89c7d4ea922586301000000000000016001422da97b29bbb5d5de50d5b8ed632374f5181135200000000" "["cR7zWWke3wEVnCsP9NHAB6uFt8Lmi7DKGceohGXPbJUiTT7hg8zd"]"

結果 獲得
{
"hex": "020000000001010c2b1a39c2dd74a672390a1da19d2c2f830b29e39da96be49fd87eedb17116510200000000ffffffff02e80300000000000016001452ffe1674d360e138406549d2e89c7d4ea922586301000000000000016001422da97b29bbb5d5de50d5b8ed632374f518113520247304402207d86656d7033b7388f1ab233b8b7f70fa21a837264422c772f989ccc4f9b754b02206c73639bbb0bca909e7671d6f1e5f9d335ef1a3e8298108ab41399fff1dd1c60012102f89309da92f327e9e8b547f72b9563deaee2deef9bfc2803991df4dd48d67cdd00000000",
"complete": true
}

發送交易 (鏈上交易)
參數 1 signrawtransactionwithkey 步驟的 hex 結果
curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "sendrawtransaction", "params": ["020000000001010c2b1a39c2dd74a672390a1da19d2c2f830b29e39da96be49fd87eedb17116510200000000ffffffff02e80300000000000016001452ffe1674d360e138406549d2e89c7d4ea922586301000000000000016001422da97b29bbb5d5de50d5b8ed632374f518113520247304402207d86656d7033b7388f1ab233b8b7f70fa21a837264422c772f989ccc4f9b754b02206c73639bbb0bca909e7671d6f1e5f9d335ef1a3e8298108ab41399fff1dd1c60012102f89309da92f327e9e8b547f72b9563deaee2deef9bfc2803991df4dd48d67cdd00000000"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

拿到交易的 txhash
{"result":"ec53925fc146a3a77a85d3a4f11cb1c815d6a0707733167ffa595245c848704a","error":null,"id":"curltest"}

此交易的 txhash 可以在區塊鏈上查詢

獲取原生交易
參數 1 signrawtransactionwithkey 步驟的 hex 結果
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 decoderawtransaction 020000000001010c2b1a39c2dd74a672390a1da19d2c2f830b29e39da96be49fd87eedb17116510200000000ffffffff02e80300000000000016001452ffe1674d360e138406549d2e89c7d4ea922586301000000000000016001422da97b29bbb5d5de50d5b8ed632374f518113520247304402207d86656d7033b7388f1ab233b8b7f70fa21a837264422c772f989ccc4f9b754b02206c73639bbb0bca909e7671d6f1e5f9d335ef1a3e8298108ab41399fff1dd1c60012102f89309da92f327e9e8b547f72b9563deaee2deef9bfc2803991df4dd48d67cdd00000000

測試帳號

​​​​"secret_key":"cTbLF5UtcULPLd8G7CENxSbBQ2dyKsPzjGKEtADoN3ToPfpojLUG",
​​​​"from_address":"tb1q9f6zrdhd8rzuxcv2erfnnqa5yk4shguzm6mrre",

​​​​ "secret_key":"cQQ3cEz2x7K4t9KPVFRttgWNBSsbEhpFkXLdz4vqm7SnHTFchB44",
​​​​"from_address":"tb1qjzz6gzq4c4a4fksx2jccgnwc49h8y59n5dam43",

curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "listunspent", "params": [0, 9999999, ["tb1q9f6zrdhd8rzuxcv2erfnnqa5yk4shguzm6mrre"] , true ]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

0.0000444

curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "listunspent", "params": [0, 9999999, ["tb1qqcqpu8e8lrcpet7nx3v6jytqvrcxk0rje362uu"] , true ]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

===================================================================================================

curl user bitcoinrpc:btc2018 data-binary '{"jsonrpc": "1.0", "id": "testwallet", "method": "dumpprivkey", "params": ["tb1qp6cw8tr9nturxa3jl9x787kfscf20vuz33jjda"]}' -H 'content-type: text/plain;' http://127.0.0.1:18332/

{"result":"cQVp5g9hoCjshXvV1yzLe4aPRtBCP9HctYXAWCqFDxZqCQJjhKLx","error":null,"id":"testwallet"}

目前餘額 0.00029009 - 0.00001 - 0.00000685 = 0.00027324

創建原始交易 2
參數 2 目的地址和收到的金額, 來源地址和此小錢包最後餘額
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 createrawtransaction "[]" "[{"tb1qje93dmw9vpth9yx7llmfm2v86kcy3kel0g2tvl":0.00001},{"tb1qytdf0v5mhdw4megdtw8dvv3hfagczy6ju26d3e":0.00028009}]"

充值裸交易
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 fundrawtransaction 020000000002e803000000000000160014964b16edc560577290defff69da987d5b048db3f696d00000000000016001422da97b29bbb5d5de50d5b8ed632374f5181135200000000

用私鑰簽署原始交易
bitcoin-cli -rpcuser=bitcoinrpc -rpcpassword=btc2018 -rpcport=18332 signrawtransactionwithkey "0200000009afa1fecbd03d23238061c1b09547031061dfd05d4046eec5a8d5b5d4470566c80000000000feffffff290b006e34f62959a7714656c8286f9e69a386e65bb409abc49e6e1116866bdd0000000000feffffff04a8700b5f7b52d9bf39c652e84353074a2e0b364f23b8e78c778c498b1409330200000000feffffff3f6c0eac0ba77712ec1fb157e6d59e0505fe1f8eaae0334b61cee017945377160000000000fefffffff34ea431476d637324857bf5c6de79328782a9257904a169d76590a4e26585af0100000000feffffffa870bf0a355e6c36d292a4e4fbbe758527c987d1fd951dc7df0f1a606506ed930000000000feffffff468614705f01b12ccf12c5c1a2c463509382aae5c7067952f1b18481271625c10200000000feffffff2c2816a54b109096ca8846e3fb3967918fd23edf55251197551b98278bc59cb80100000000feffffff2c2816a54b109096ca8846e3fb3967918fd23edf55251197551b98278bc59cb80000000000feffffff02e803000000000000160014964b16edc560577290defff69da987d5b048db3f696d00000000000016001422da97b29bbb5d5de50d5b8ed632374f5181135200000000" "["cQVp5g9hoCjshXvV1yzLe4aPRtBCP9HctYXAWCqFDxZqCQJjhKLx"]"

bitcoin.conf

###### RPC 配置 ###### testnet=1 # 0-主网 1-测试网 rpcallowip=0.0.0.0/16 # rpc访问白名单 datadir=/data/btc_data # 区块存储位置(硬盘要够用) dbcache=10240 # 所有交易进行索引; 否则只保留钱包地址交易索引记录 rpcuser=bitcoinrpc # RPC 远程连接的认证用户名 rpcpassword=btc2018 # RPC 远程连接的认证用密碼 txindex=1 # daemon=1 # 是否后台运行 server=1 # 是否启动JSON-RPC接口 (0-不启动 1-启动) #rest=1 #rpcbind=0.0.0.0 # rpc接口的监听地址,默认绑定到所有IP mainnet 才要開 #rpcport=8332 # rpc接口的监听端口 mainnet 專用port mainnet 才要開 deprecatedrpc=signrawtransaction walletnotify=sh /root/data/notify_btc/notify.sh %s #通知到账 rpctimeout=30 # rpc客户端超时秒数 maxconnections=200 # 入站/出站最大连接数 ###### 钱包配置 ###### #paytxfee=0.00 # 每次发送比特币时的交易费 #txconfirmtarget=6 # 交易最小确认数 (默认值: 6)

ETH

eth教學
智能合約學習中
測試鏈,水龍頭

搭建 ETH 節點

version: 1.10.26

創建項目目錄

創建並進入 eth 節點目錄

mkdir -p /data/eth_data && cd /data/eth_data

mkdir -p node
mkdir -p node_prysm

下載可執行文件

wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.11.2-73b01f40.tar.gz
tar xvfz geth-linux-amd64-1.11.2-73b01f40.tar.gz
cd /data/eth_data && cp ./geth-linux-amd64-1.11.2-73b01f40/geth ./
wget https://github.com/eth-clients/eth2-networks/raw/master/shared/prater/genesis.ssz

curl https://raw.githubusercontent.com/prysmaticlabs/prysm/master/prysm.sh --output prysm.sh && chmod +x prysm.sh

啟動節點

# 生成 JWT 認證
./prysm.sh beacon-chain generate-auth-secret
# 啟動 信標節點
vim start_prysm.sh
#!/bin/bash
echo "prysm testnet prater"
screen -dmS prysm ./prysm.sh beacon-chain \
           --execution-endpoint=http://localhost:8551 \
           --jwt-secret=./jwt.hex \
           --genesis-state=./genesis.ssz \
           --suggested-fee-recipient=0x01234567722E6b0000012BFEBf6177F1D2e9758D9 \
           --datadir ./node_prysm \
           --prater
chmod +x start_prysm.sh
./start_prysm.sh
vim start.sh
#!/bin/bash
echo "Starting private ETH testnet"
screen -dmS ETH_testnet ./geth \
            --goerli \
            --datadir ./node \
            --syncmode full \
            --gcmode archive \
            --cache 1024 \
            --http \
            --http.addr 0.0.0.0 \
            --http.port 8545 \
            --http.api eth,net,engine,admin \
            --authrpc.jwtsecret ./jwt.hex \
            --authrpc.addr localhost \
            --authrpc.port 8551 \
            --authrpc.vhosts localhost \
            --allow-insecure-unlock
chmod +x start.sh
./start.sh

查看節點數據

# 信標節點
curl http://localhost:3500/eth/v1alpha1/node/syncing
# geth
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' http://localhost:8545

./geth attach http://127.0.0.1:8545
eth.syncing
eth.blockNumber

停止节点

使用 screen -ls 获取 session id

screen -X -S {session id} quit