Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/build_relay.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: ci_relay

# relay 集成测试:btcd(simnet) + relayd + 6 个 chain33 节点。
# 依赖 plugin/dapp/relay/cmd/build.sh 在 make build_ci 时构建 relayd 并生成
# build/ci/relay(relayd、relayd.toml、Dockerfile-relayd、docker-compose-relay.yml、
# testcase.sh),否则 make docker-compose dapp=relay 会打印
# "dapp=relay not exist or is system dir" 后直接返回 0(假绿)。
on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:

jobs:
ci_relay:
name: ci_relay
runs-on: ubuntu-22.04
timeout-minutes: 90
steps:
- name: checkout
uses: actions/checkout@v4
with:
# build 脚本用 git describe --tags 注入版本号
fetch-depth: 0

- name: Set up Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
id: go

- name: set go env
run: export PATH=${PATH}:`go env GOPATH`/bin

- name: deploy
run: |
make build_ci
make docker-compose dapp=relay

- name: cleanup
if: always()
run: make docker-compose-down dapp=relay
17 changes: 9 additions & 8 deletions plugin/dapp/relay/cmd/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}

#OUT_DIR="${1}/$strapp"
#SRC_RELAYD=github.com/33cn/plugin/plugin/dapp/relay/cmd/relayd
#FLAG=$2
#
## shellcheck disable=SC2086,1072
#go build ${FLAG} -v -o "${OUT_DIR}/relayd" "${SRC_RELAYD}"
#cp ./relayd/relayd.toml "${OUT_DIR}/relayd.toml"
#cp ./build/* "${OUT_DIR}"
OUT_DIR="${1}/$strapp"
SRC_RELAYD=github.com/33cn/plugin/plugin/dapp/relay/cmd/relayd
FLAG=$2

mkdir -p "${OUT_DIR}"
# shellcheck disable=SC2086,1072
go build ${FLAG} -v -o "${OUT_DIR}/relayd" "${SRC_RELAYD}"
cp ./relayd/relayd.toml "${OUT_DIR}/relayd.toml"
cp ./build/* "${OUT_DIR}"

OUT_TESTDIR="${1}/dapptest/$strapp"
mkdir -p "${OUT_TESTDIR}"
Expand Down
10 changes: 8 additions & 2 deletions plugin/dapp/relay/cmd/build/testcase.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ function relay_config() {
function wait_btcd_up() {
local count=20
while [ $count -gt 0 ]; do
status=$(docker-compose ps | grep btcd | awk '{print $5}')
if [ "${status}" == "Up" ]; then
# docker compose ps 列取错(取到 CREATED 列)会导致永远重启 btcd,
# 且 ubuntu-22.04 runner 只有 compose v2,这里直接用 docker inspect 判状态
status=$(docker inspect -f '{{.State.Status}}' "${BTCD}" 2>/dev/null || true)
if [ "${status}" == "running" ]; then
break
fi
docker compose logs btcd
Expand Down Expand Up @@ -334,6 +336,10 @@ function relay_test() {
count=$((count - 1))
if [ $count -le 0 ]; then
echo "wrong relay status finish real buy order id"
echo "=========== # relayd logs ==========="
docker compose logs relayd 2>&1 | tail -80
echo "=========== # chain33 relay logs ==========="
docker compose logs chain33 2>&1 | grep -iE "verify|relay" | tail -60
exit 1
fi
done
Expand Down
48 changes: 48 additions & 0 deletions plugin/dapp/relay/executor/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
package executor

import (
"bytes"
"testing"

apimock "github.com/33cn/chain33/client/mocks"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/mocks"
"github.com/33cn/chain33/types"
ty "github.com/33cn/plugin/plugin/dapp/relay/types"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"

Expand Down Expand Up @@ -372,6 +379,47 @@ func TestRunSuiteRelay(t *testing.T) {
suite.Run(t, log)
}

// TestVerifyBtcTxContentSimnet 集成测试场景回归: btcd simnet 的订单收款地址
// 必须按 simnet 网络参数解析输出地址,硬编码 MainNet 会因地址编码不一致误判
func TestVerifyBtcTxContentSimnet(t *testing.T) {
hash160 := bytes.Repeat([]byte{0xab}, 20)
addr, err := btcutil.NewAddressPubKeyHash(hash160, &chaincfg.SimNetParams)
if err != nil {
t.Fatal(err)
}
pkScript, err := txscript.PayToAddrScript(addr)
if err != nil {
t.Fatal(err)
}

msgTx := wire.NewMsgTx(2)
// Deserialize 会把 vin 数 0 当作 witness marker,因此至少带一个输入
// (真实的 btc 交易也必然有输入)
msgTx.AddTxIn(wire.NewTxIn(wire.NewOutPoint(&chainhash.Hash{}, 0xffffffff), nil, nil))
msgTx.AddTxOut(wire.NewTxOut(100000, pkScript))
var buf bytes.Buffer
if err := msgTx.SerializeNoWitness(&buf); err != nil {
t.Fatal(err)
}
rawHash := txidFromMsgTx(msgTx)
// reverse 原地修改切片,先拷贝一份作为期望值
want := append([]byte{}, rawHash...)
btcTx := &ty.BtcTransaction{
Hash: common.ToHex(reverse(rawHash)),
RawTx: common.ToHex(buf.Bytes()),
}
spv := &ty.BtcSpv{Hash: btcTx.Hash}
order := &ty.RelayOrder{XAddr: addr.EncodeAddress(), XAmount: 100000}

got, err := verifyBtcTxContent(btcTx, spv, order)
if err != nil {
t.Fatalf("verifyBtcTxContent simnet addr: %v", err)
}
if !bytes.Equal(got, want) {
t.Fatalf("verifyBtcTxContent rawHash mismatch, got %x want %x", got, want)
}
}

//////////////////////////////////////

type suiteBtcHeader struct {
Expand Down
22 changes: 21 additions & 1 deletion plugin/dapp/relay/executor/relaybtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/types"
ty "github.com/33cn/plugin/plugin/dapp/relay/types"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
Expand Down Expand Up @@ -342,9 +343,13 @@ func verifyBtcTxContent(btcTx *ty.BtcTransaction, spv *ty.BtcSpv, order *ty.Rela
return nil, ty.ErrRelayBtcTxHashErr
}

// 订单收款地址可能属于任一 btc 网络(集成测试为 simnet),
// 用能成功解码订单地址的网络参数解析输出地址,
// 否则硬编码 MainNet 会把 simnet 输出地址重编码成 mainnet 地址,永远匹配不上
params := addrNetParams(order.XAddr)
var foundtx bool
for _, out := range msgTx.TxOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(out.PkScript, &chaincfg.MainNetParams)
_, addrs, _, err := txscript.ExtractPkScriptAddrs(out.PkScript, params)
if err != nil {
continue
}
Expand Down Expand Up @@ -390,6 +395,21 @@ func (b *btcStore) verifyCmdBtcTx(verify *ty.RelayVerifyCli) error {
return nil
}

// addrNetParams 返回能成功解码 addr 的 btc 网络参数,全部失败时回退 MainNet
func addrNetParams(addr string) *chaincfg.Params {
for _, p := range []*chaincfg.Params{
&chaincfg.MainNetParams,
&chaincfg.TestNet3Params,
&chaincfg.RegressionNetParams,
&chaincfg.SimNetParams,
} {
if _, err := btcutil.DecodeAddress(addr, p); err == nil {
return p
}
}
return &chaincfg.MainNetParams
}

// decodeRawTx 将 hex 编码的原始 btc 交易反序列化为 MsgTx
func decodeRawTx(rawTx string) (*wire.MsgTx, error) {
data, err := common.FromHex(rawTx)
Expand Down
Loading