An open API service indexing awesome lists of open source software.

https://github.com/nervosnetwork/ckb-types-go


https://github.com/nervosnetwork/ckb-types-go

Last synced: over 1 year ago
JSON representation

Awesome Lists containing this project

README

          

# ckb-types-go

[![Actions Status](https://github.com/zeroqn/ckb-types-go/workflows/Go/badge.svg)](https://github.com/zeroqn/ckb-types-go/actions)

### Note

Encode `Transaction` will strip witnesses field, so that
we can properly calculate transaction hash.

### example

#### send capacity

```go
package main

import (
"encoding/binary"
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/minio/blake2b-simd"
t "github.com/nervosnetwork/ckb-types-go/jsonrpc/types"
"github.com/ybbus/jsonrpc"
)

// from spec/dev.toml
// # issue 10M cell for random generated private key: d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc
// [[genesis.issued_cells]]
// capacity = 10_000_000_00000000
// lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"
// lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7"
// lock.hash_type = "type"
//
// # issue 5M cell for random generated private key: 63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d
// [[genesis.issued_cells]]
// capacity = 5_000_000_00000000
// lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"
// lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7"
// lock.hash_type = "type"

// CkbBlake2BHashPersonalization personal
const CkbBlake2BHashPersonalization = "ckb-default-hash"

// GenesisBlockHash genesis block hash
const GenesisBlockHash = "0x73f4ffa1d7898c2c044326363ba8d59fd123e173ff2d5c4d187d29baaae6214e"

// BobAddress bob address
const BobAddress = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7"

// BobSecKey bob private key
const BobSecKey = "d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc"

// AliceAddress Alice address
const AliceAddress = "0x470dcdc5e44064909650113a274b3b36aecb6dc7"

// SystemCellLockCodeHash system cell lock code hash
const SystemCellLockCodeHash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"

// M5 5 millions
const M5 = "0x1c6bf52634000"

// M49 4.9 millions
const M49 = "0x1bda703f0a000"

// M10 10 millions
const M10 = "0x38d7ea4c68000"

// RPCResultTransaction transaction response from jsonrpc
type RPCResultTransaction struct {
Version t.Uint32 `json:"version"`
Hash string `json:"hash"`
CellDeps []t.CellDep `json:"cell_deps"`
HeaderDeps []t.Hash `json:"header_deps"`
Inputs []t.CellInput `json:"inputs"`
Outputs []t.CellOutput `json:"outputs"`
Witnesses []t.Bytes `json:"witnesses"`
OutputsData []t.Bytes `json:"outputs_data"`
}

// RPCResultBlock block response from jsonrpc
type RPCResultBlock struct {
Header t.Header `json:"header"`
Proposals []t.ProposalShortID `json:"proposals"`
Transactions []RPCResultTransaction `json:"transactions"`
Uncles []t.UncleBlock `json:"uncles"`
}

func main() {
rpcClient := jsonrpc.NewClient("http://127.0.0.1:8114")

resp, err := rpcClient.Call("get_block", GenesisBlockHash)
if err != nil {
fmt.Printf("Err %v", err)
return
}

genesisBlock := new(RPCResultBlock)

err = resp.GetObject(&genesisBlock)
if err != nil || genesisBlock == nil {
fmt.Printf("Unmarsh json genesisBlock fail: %v", err)
}

if genesisBlock.Transactions[0].Outputs[6].Lock.Args != BobAddress {
fmt.Println("Genesis bob address changed")
return
}

if genesisBlock.Transactions[0].Outputs[7].Lock.Args != AliceAddress {
fmt.Println("Genesis alice address changed")
return
}

// We try to transfer 5M from bob to alice

// Calc cell deps
secpDepGroup := genesisBlock.Transactions[1].Hash
outpoint := t.OutPoint{
TxHash: t.Hash(secpDepGroup),
Index: "0x0",
}

cellDep := t.CellDep{
OutPoint: outpoint,
DepType: t.DepGroup,
}

// Calc input
bobPrevOutPoint := t.OutPoint{
TxHash: t.Hash(genesisBlock.Transactions[0].Hash),
Index: "0x6",
}

bobInput := t.CellInput{
PreviousOutput: bobPrevOutPoint,
Since: "0x0",
}

// Calc outputs
aliceScript := t.Script{
Args: AliceAddress,
CodeHash: SystemCellLockCodeHash,
HashType: t.Type,
}

aliceOutput := t.CellOutput{
Capacity: M5,
Lock: aliceScript,
Type: nil,
}

bobScript := t.Script{
Args: BobAddress,
CodeHash: SystemCellLockCodeHash,
HashType: t.Type,
}

bobOutput := t.CellOutput{
Capacity: M49,
Lock: bobScript,
Type: nil,
}

// Assemble transaction
tx := t.Transaction{
Version: "0x0",
CellDeps: []t.CellDep{cellDep},
HeaderDeps: make([]t.Hash, 0),
Inputs: []t.CellInput{bobInput},
Outputs: []t.CellOutput{aliceOutput, bobOutput},
Witnesses: make([]t.Bytes, 0),
OutputsData: []t.Bytes{"0x", "0x"},
}

// Cacl witness

// Serialize transaction
txBlob, err := tx.Serialize()
if err != nil {
fmt.Printf("Encode failure: %s", err)
return
}

// Prepare hash
config := &blake2b.Config{
Size: 32,
Person: []byte(CkbBlake2BHashPersonalization),
}
h, err := blake2b.New(config)
if err != nil {
fmt.Printf("Initial blake2b hash failure, %s\n", err)
return
}

// Hash tx
h.Write(txBlob)
txHash := h.Sum(nil)

// Calc witness args
// 65 is secp256k1 signature length
lock := hex.EncodeToString(make([]byte, 65))
witnessLock := t.Bytes(fmt.Sprintf("0x%s", lock))
wa := t.WitnessArgs{
Lock: &witnessLock,
}

wab, err := wa.Serialize()
if err != nil {
fmt.Printf("Serialize witness args failure, %s\n", err)
return
}

wabLen := make([]byte, 8)
binary.LittleEndian.PutUint64(wabLen, uint64(len(wab)))

// Hash again
h.Reset()
h.Write(txHash)
h.Write(wabLen)
h.Write(wab)
witnessMessage := h.Sum(nil)

// Sign witness message
bobSecKey := make([]byte, 32)
_, err = hex.Decode(bobSecKey, []byte(BobSecKey))
if err != nil {
fmt.Println("Invalid bob private key")
return
}

witnessSig, err := secp256k1.Sign(witnessMessage[:], bobSecKey)
if err != nil {
fmt.Printf("Calc witness failure: %s\n", err)
return
}

// Hex witness signature
// 130 is hexed secp256k1 with recoverable public length
witness := make([]byte, 130)
hex.Encode(witness, witnessSig[:])

// Refill witness args
witnessLock = t.Bytes(fmt.Sprintf("0x%s", witness))
wa = t.WitnessArgs{
Lock: &witnessLock,
}

// Serialize witness args
witness, err = wa.Serialize()
if err != nil {
fmt.Printf("witness serialize failure: %s\n", err)
return
}

// Update transaction with witness
tx.Witnesses = []t.Bytes{t.Bytes(fmt.Sprintf("0x%s", hex.EncodeToString(witness)))}

resp, err = rpcClient.Call("send_transaction", []*t.Transaction{&tx})
if err != nil {
fmt.Printf("Err %v", err)
return
}

fmt.Printf("transfer response %v", resp)
}
```