Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Channel Service #1

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "perun-wallet-spec"]
path = perun-wallet-spec
url = [email protected]:perun-network/perun-wallet-spec
159 changes: 159 additions & 0 deletions deployment/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package deployment

import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"

"github.com/nervosnetwork/ckb-sdk-go/v2/types"
"perun.network/perun-ckb-backend/backend"
)

const PFLSMinCapacity = 4100000032

type SUDTInfo struct {
Script *types.Script
CellDep *types.CellDep
}

type Migration struct {
CellRecipes []struct {
Name string `json:"name"`
TxHash string `json:"tx_hash"`
Index uint32 `json:"index"`
OccupiedCapacity int64 `json:"occupied_capacity"`
DataHash string `json:"data_hash"`
TypeId interface{} `json:"type_id"`
} `json:"cell_recipes"`
DepGroupRecipes []interface{} `json:"dep_group_recipes"`
}

func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) {
pcts := m.CellRecipes[0]
if pcts.Name != "pcts" {
return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("first cell recipe must be pcts")
}
pcls := m.CellRecipes[1]
if pcls.Name != "pcls" {
return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("second cell recipe must be pcls")
}
pfls := m.CellRecipes[2]
if pfls.Name != "pfls" {
return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("third cell recipe must be pfls")
}
sudtInfo, err := m.GetSUDT()
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}
// NOTE: The SUDT lock-arg always contains a newline character at the end.
hexString := strings.ReplaceAll(sudtOwnerLockArg[2:], "\n", "")
hexString = strings.ReplaceAll(hexString, "\r", "")
hexString = strings.ReplaceAll(hexString, " ", "")
sudtInfo.Script.Args, err = hex.DecodeString(hexString)
if err != nil {
return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("invalid sudt owner lock arg: %v", err)
}

return backend.Deployment{
Network: types.NetworkTest,
PCTSDep: types.CellDep{
OutPoint: &types.OutPoint{
TxHash: types.HexToHash(pcts.TxHash),
Index: m.CellRecipes[0].Index,
},
DepType: types.DepTypeCode,
},
PCLSDep: types.CellDep{
OutPoint: &types.OutPoint{
TxHash: types.HexToHash(pcls.TxHash),
Index: m.CellRecipes[0].Index,
},
DepType: types.DepTypeCode,
},
PFLSDep: types.CellDep{
OutPoint: &types.OutPoint{
TxHash: types.HexToHash(pfls.TxHash),
Index: m.CellRecipes[0].Index,
},
DepType: types.DepTypeCode,
},
PCTSCodeHash: types.HexToHash(pcts.DataHash),
PCTSHashType: types.HashTypeData1,
PCLSCodeHash: types.HexToHash(pcls.DataHash),
PCLSHashType: types.HashTypeData1,
PFLSCodeHash: types.HexToHash(pfls.DataHash),
PFLSHashType: types.HashTypeData1,
PFLSMinCapacity: PFLSMinCapacity,
DefaultLockScript: types.Script{
CodeHash: systemScripts.Secp256k1Blake160SighashAll.ScriptID.CodeHash,
HashType: systemScripts.Secp256k1Blake160SighashAll.ScriptID.HashType,
Args: make([]byte, 32),
},
DefaultLockScriptDep: systemScripts.Secp256k1Blake160SighashAll.CellDep,
SUDTDeps: map[types.Hash]types.CellDep{
sudtInfo.Script.Hash(): *sudtInfo.CellDep,
},
SUDTs: map[types.Hash]types.Script{
sudtInfo.Script.Hash(): *sudtInfo.Script,
},
}, *sudtInfo, nil
}

func (m Migration) GetSUDT() (*SUDTInfo, error) {
sudt := m.CellRecipes[3]
if sudt.Name != "sudt" {
return nil, fmt.Errorf("fourth cell recipe must be sudt")
}

sudtScript := types.Script{
CodeHash: types.HexToHash(sudt.DataHash),
HashType: types.HashTypeData1,
Args: []byte{},
}
sudtCellDep := types.CellDep{
OutPoint: &types.OutPoint{
TxHash: types.HexToHash(sudt.TxHash),
Index: sudt.Index,
},
DepType: types.DepTypeCode,
}
return &SUDTInfo{
Script: &sudtScript,
CellDep: &sudtCellDep,
}, nil
}

func GetDeployment(migrationDir, systemScriptsDir, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) {
dir, err := os.ReadDir(migrationDir)
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}
if len(dir) != 1 {
return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("migration dir must contain exactly one file")
}
migrationName := dir[0].Name()
migrationFile, err := os.Open(path.Join(migrationDir, migrationName))
defer migrationFile.Close()
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}
migrationData, err := io.ReadAll(migrationFile)
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}
var migration Migration
err = json.Unmarshal(migrationData, &migration)
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}

ss, err := GetSystemScripts(systemScriptsDir)
if err != nil {
return backend.Deployment{}, SUDTInfo{}, err
}
return migration.MakeDeployment(ss, sudtOwnerLockArg)
}
33 changes: 33 additions & 0 deletions deployment/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package deployment

import (
"encoding/hex"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"io"
"os"
"strings"
)

func GetKey(path string) (*secp256k1.PrivateKey, error) {
keyFile, err := os.Open(path)
if err != nil {
return nil, err
}
defer keyFile.Close()

rawBytes, err := io.ReadAll(keyFile)
if err != nil {
return nil, err
}
lines := strings.Split(string(rawBytes), "\n")
if len(lines) != 2 {
return nil, fmt.Errorf("key file must contain exactly two lines")
}
x := strings.Trim(lines[0], " \n")
xBytes, err := hex.DecodeString(x)
if err != nil {
return nil, err
}
return secp256k1.PrivKeyFromBytes(xBytes), nil
}
58 changes: 58 additions & 0 deletions deployment/system_scripts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package deployment

import (
"encoding/json"
"io"
"os"
"path"

"github.com/nervosnetwork/ckb-sdk-go/v2/types"
)

type SystemScripts struct {
DAO struct {
CellDep types.CellDep `json:"cell_dep"`
ScriptID ScriptID `json:"script_id"`
} `json:"dao"`
Secp256k1Blake160MultisigAll struct {
CellDep types.CellDep `json:"cell_dep"`
ScriptID ScriptID `json:"script_id"`
} `json:"secp256k1_blake160_multisig_all"`
Secp256k1Blake160SighashAll struct {
CellDep types.CellDep `json:"cell_dep"`
ScriptID ScriptID `json:"script_id"`
} `json:"secp256k1_blake160_sighash_all"`
Secp256k1Data types.OutPoint `json:"secp256k1_data"`
TypeID struct {
ScriptID ScriptID `json:"script_id"`
} `json:"type_id"`
}

type ScriptID struct {
CodeHash types.Hash `json:"code_hash"`
HashType types.ScriptHashType `json:"hash_type"`
}

const systemScriptName = "default_scripts.json"

func GetSystemScripts(systemScriptDir string) (SystemScripts, error) {
var ss SystemScripts
err := readJSON(systemScriptDir, &ss)
if err != nil {
return SystemScripts{}, err
}
return ss, nil
}

func readJSON(systemScriptDir string, systemScripts *SystemScripts) error {
systemScriptFile, err := os.Open(path.Join(systemScriptDir, systemScriptName))
defer func() { _ = systemScriptFile.Close() }()
if err != nil {
return err
}
systemScriptContent, err := io.ReadAll(systemScriptFile)
if err != nil {
return err
}
return json.Unmarshal(systemScriptContent, systemScripts)
}
21 changes: 21 additions & 0 deletions deployment/system_scripts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package deployment_test

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/require"
"perun.network/channel-service/deployment"
)

func TestSystemScripts(t *testing.T) {
var ss deployment.SystemScripts
require.NoError(t, json.Unmarshal([]byte(systemScriptCase), &ss))
msg, err := json.Marshal(ss)
require.NoError(t, err)
recovered := new(deployment.SystemScripts)
require.NoError(t, json.Unmarshal(msg, recovered))
require.Equal(t, ss, *recovered)
}

var systemScriptCase string = "{\"dao\":{\"cell_dep\":{\"dep_type\":\"code\",\"out_point\":{\"index\":\"0x2\",\"tx_hash\":\"0x297d19805fee99a53a6274a976df562d678beeff286776e1cd5ac9d8e1870780\"}},\"script_id\":{\"code_hash\":\"0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e\",\"hash_type\":\"type\"}},\"secp256k1_blake160_multisig_all\":{\"cell_dep\":{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x1\",\"tx_hash\":\"0xad69fbce31c6d8a8516789dec3cd4ddecbeb63619b4fa6cd3a7d00cdc788bf33\"}},\"script_id\":{\"code_hash\":\"0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8\",\"hash_type\":\"type\"}},\"secp256k1_blake160_sighash_all\":{\"cell_dep\":{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":\"0xad69fbce31c6d8a8516789dec3cd4ddecbeb63619b4fa6cd3a7d00cdc788bf33\"}},\"script_id\":{\"code_hash\":\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":\"type\"}},\"secp256k1_data\":{\"out_point\":{\"index\":\"0x3\",\"tx_hash\":\"0x297d19805fee99a53a6274a976df562d678beeff286776e1cd5ac9d8e1870780\"}},\"type_id\":{\"script_id\":{\"code_hash\":\"0x00000000000000000000000000000000000000000000000000545950455f4944\",\"hash_type\":\"type\"}}}"
49 changes: 36 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,48 @@ module perun.network/channel-service
go 1.19

require (
google.golang.org/grpc v1.58.2
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0
github.com/stretchr/testify v1.8.4
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
perun.network/go-perun v0.10.6
perun.network/go-perun v0.10.7-0.20230808153546-74844191e56e
perun.network/perun-ckb-backend v0.0.0-20231026110519-7a17b08740d8
)

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Pilatuz/bigz v1.2.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
github.com/ethereum/go-ethereum v1.13.4 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/holiman/uint256 v1.2.3 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
polycry.pt/poly-go v0.0.0-20220222131629-aa4bdbaab60b // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/objx v0.5.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 // indirect
)

replace github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 => github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20230601140721-2bf596fddd80
Loading