diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9889f9..922236d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,39 +119,61 @@ jobs: go run . docker stop polkadot - - name: Payment Channel CKB - working-directory: payment-channel-ckb + + - name: Install CKB contract dependencies run: | sudo apt-get update - sudo apt-get install -y jq sed gawk tmux tmuxp expect make - curl -LO https://github.com/nervosnetwork/ckb/releases/download/v0.109.0/ckb_v0.109.0_x86_64-unknown-linux-gnu.tar.gz - tar -xzf ckb_v0.109.0_x86_64-unknown-linux-gnu.tar.gz - sudo cp ckb_v0.109.0_x86_64-unknown-linux-gnu/ckb /usr/local/bin/ - curl -LO https://github.com/nervosnetwork/ckb-cli/releases/download/v1.4.0/ckb-cli_v1.4.0_x86_64-unknown-linux-gnu.tar.gz - tar -xzf ckb-cli_v1.4.0_x86_64-unknown-linux-gnu.tar.gz - sudo cp ckb-cli_v1.4.0_x86_64-unknown-linux-gnu/ckb-cli /usr/local/bin/ - curl -LO https://github.com/nervosnetwork/capsule/releases/download/v0.9.2/capsule_v0.9.2_x86_64-linux.tar.gz - tar -xzf capsule_v0.9.2_x86_64-linux.tar.gz - sudo cp capsule_v0.9.2_x86_64-linux/capsule /usr/local/bin/ - wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb - sudo dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb - cd ./devnet - chmod +x setup-devnet.sh print_accounts.sh deploy_contracts.sh sudt_helper.sh - ./setup-devnet.sh - ckb run > /dev/null 2>&1 & - sleep 3 - ckb miner > /dev/null 2>&1 & - sleep 3 - ./print_accounts.sh - sleep 6 - expect fund_accounts.expect - sleep 10 - ./deploy_contracts.sh - sleep 15 - ./sudt_helper.sh fund - sleep 10 - ./sudt_helper.sh balances + sudo apt-get install -y gcc-riscv64-unknown-elf binutils-riscv64-unknown-elf libc6-dev-riscv64-cross libc6-riscv64-cross linux-libc-dev-riscv64-cross + wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 18 && rm llvm.sh + cargo install cargo-generate + rustup target add riscv64imac-unknown-none-elf + + - name: Create Symlink + run: sudo ln -s /usr/riscv64-linux-gnu/include/gnu/stubs-lp64d.h /usr/riscv64-linux-gnu/include/gnu/stubs-lp64.h + - name: Start devnet in background + working-directory: payment-channel-ckb + env: + RUSTFLAGS: "-C linker=rust-lld" + CARGO_TARGET_RISCV64IMAC_UNKNOWN_NONE_ELF_LINKER: rust-lld + CC_riscv64imac_unknown_none_elf: riscv64-unknown-elf-gcc + AR_riscv64imac_unknown_none_elf: riscv64-unknown-elf-ar + C_INCLUDE_PATH: /usr/riscv64-linux-gnu/include + CFLAGS: "-I/usr/riscv64-linux-gnu/include" + TARGET_CFLAGS: "-I/usr/riscv64-linux-gnu/include" + run: | + sudo apt-get update + sudo apt-get install -y jq sed gawk tmux tmuxp expect make + curl -LO https://github.com/nervosnetwork/ckb/releases/download/v0.201.0/ckb_v0.201.0_x86_64-unknown-linux-gnu.tar.gz + tar -xzf ckb_v0.201.0_x86_64-unknown-linux-gnu.tar.gz + sudo cp ckb_v0.201.0_x86_64-unknown-linux-gnu/ckb /usr/local/bin/ + curl -LO https://github.com/nervosnetwork/ckb-cli/releases/download/v1.4.0/ckb-cli_v1.4.0_x86_64-unknown-linux-gnu.tar.gz + curl -LO https://github.com/nervosnetwork/ckb-cli/releases/download/v1.13.0/ckb-cli_v1.13.0_x86_64-unknown-linux-gnu.tar.gz + tar -xzf ckb-cli_v1.13.0_x86_64-unknown-linux-gnu.tar.gz + sudo cp ckb-cli_v1.13.0_x86_64-unknown-linux-gnu/ckb-cli /usr/local/bin/ + wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb + sudo dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb + + git submodule update --init --recursive + cd ./devnet + chmod +x setup-devnet.sh print_accounts.sh deploy_contracts.sh sudt_helper.sh + ./setup-devnet.sh + ckb run > /dev/null 2>&1 & + sleep 3 + ckb miner > /dev/null 2>&1 & + sleep 3 + ./print_accounts.sh + sleep 6 + expect fund_accounts.expect + sleep 10 + ./deploy_contracts.sh + sleep 15 + ./sudt_helper.sh fund + sleep 10 + ./sudt_helper.sh balances + cd ../.. + - name: Payment Channel CKB + working-directory: payment-channel-ckb + run: | sleep 30 - cd .. - go run main.go \ No newline at end of file + go run . diff --git a/app-channel/contracts/perun-eth-contracts b/app-channel/contracts/perun-eth-contracts index 01699bf..88b3ce2 160000 --- a/app-channel/contracts/perun-eth-contracts +++ b/app-channel/contracts/perun-eth-contracts @@ -1 +1 @@ -Subproject commit 01699bf3e63695a6c6cf8142d0a54c91c97aaa34 +Subproject commit 88b3ce254417b554e1151ff709b72dadac2753ba diff --git a/payment-channel-ckb/README.md b/payment-channel-ckb/README.md new file mode 100644 index 0000000..727f47c --- /dev/null +++ b/payment-channel-ckb/README.md @@ -0,0 +1,43 @@ +# Payment Chanenl on CKB + +This demo connects to our [Perun-CKB-Contracts] that run on the Local CKB Devnet byusing our [CKB Backend]. + +## Requirement +We use various tools to enable a convenient setup for the local development devnet. If you want to use our `setup-devnet.sh` script, make sure the following commandline tools are installed: +* `jq`: + - Used to parse and edit some configuration files. +* `sed` and `awk`: + - We modify some fields of the files generated by the `ckb init --chain dev` command using `sed` and `awk`. +* `tmux` and `tmuxp`: + - `tmuxp` is a session manager for `tmux` that allows to easily create descriptive `.yaml` configuration files to create and attach to `tmux` sessions. +* `expect`: + - We completely automize the process for test-wallet creation, deploying of contracts etc. To make this work reliably, we use `expect` which allows to describe how a commandline application is fed input. +* `make`: + - Not strictly necessary, but it should be available on most systems by default. In case you do not want to install `make` check out the `Makefile` content and issue the command on your own. +* `ckb` with version `0.201.0` or higher. +* `ckb-cli` with version `1.13.0` or higher. + +Also follow the installation of [Perun-CKB-Contracts] requirements. + +Before going through the demo, initialize the submodule. +``` +git submodule update --init --recursive +``` + +## Example Walkthrough +1. In another terminal, start the local CKB Devnet and wait 10-15 seconds for the contracts' deployment: +```sh +cd devnet +make dev +``` + +1. On the second terminal, run the demo. +```sh +cd payment-channel-ckb +go run . +``` + + +[Perun-CKB-Contracts]: https://github.com/perun-network/perun-ckb-contract/ + +[CKB Backend]: https://github.com/perun-network/perun-ckb-backend \ No newline at end of file diff --git a/payment-channel-ckb/client/balances.go b/payment-channel-ckb/client/balances.go index 2e658cc..6da6b72 100644 --- a/payment-channel-ckb/client/balances.go +++ b/payment-channel-ckb/client/balances.go @@ -26,6 +26,7 @@ import ( "github.com/nervosnetwork/ckb-sdk-go/v2/indexer" "github.com/nervosnetwork/ckb-sdk-go/v2/types" + "perun.network/perun-ckb-backend/channel" "perun.network/perun-ckb-backend/wallet/address" ) @@ -45,7 +46,7 @@ func sudtBalanceExtractor(cell *indexer.LiveCell) *big.Int { func (p *PaymentClient) PollBalances() { pollingInterval := time.Second searchKey := &indexer.SearchKey{ - Script: address.AsParticipant(p.Account.Address()).PaymentScript, + Script: address.AsParticipant(p.WalletAddress()[channel.CKBBackendID]).PaymentScript, ScriptType: types.ScriptTypeLock, ScriptSearchMode: types.ScriptSearchModeExact, Filter: nil, diff --git a/payment-channel-ckb/client/channel.go b/payment-channel-ckb/client/channel.go index 766dfba..5ddda0e 100644 --- a/payment-channel-ckb/client/channel.go +++ b/payment-channel-ckb/client/channel.go @@ -20,6 +20,7 @@ import ( "perun.network/go-perun/channel" "perun.network/go-perun/client" + "perun.network/perun-ckb-backend/channel/asset" ) type PaymentChannel struct { @@ -46,14 +47,21 @@ func (c PaymentChannel) SendPayment(amounts map[channel.Asset]float64) { actor := c.ch.Idx() peer := 1 - actor for a, amount := range amounts { - if amount < 0 { continue } - - shannonAmount := CKByteToShannon(big.NewFloat(amount)) - state.Allocation.TransferBalance(actor, peer, a, shannonAmount) - + switch a := a.(type) { + case *asset.Asset: + if a.IsCKBytes { + shannonAmount := CKByteToShannon(big.NewFloat(amount)) + state.Allocation.TransferBalance(actor, peer, a, shannonAmount) + } else { + sudtAmmount := new(big.Int).SetUint64(uint64(amount)) + state.Allocation.TransferBalance(actor, peer, a, sudtAmmount) + } + default: + panic("Asset is not of type *asset.Asset") + } } }) diff --git a/payment-channel-ckb/client/client.go b/payment-channel-ckb/client/client.go index 9d6cdb2..07edf96 100644 --- a/payment-channel-ckb/client/client.go +++ b/payment-channel-ckb/client/client.go @@ -23,14 +23,13 @@ import ( "github.com/nervosnetwork/ckb-sdk-go/v2/rpc" "github.com/nervosnetwork/ckb-sdk-go/v2/types" "github.com/perun-network/perun-libp2p-wire/p2p" - "perun.network/go-perun/channel" gpchannel "perun.network/go-perun/channel" - "perun.network/go-perun/channel/persistence" "perun.network/go-perun/client" gpwallet "perun.network/go-perun/wallet" "perun.network/go-perun/watcher/local" "perun.network/go-perun/wire" "perun.network/perun-ckb-backend/backend" + "perun.network/perun-ckb-backend/channel" "perun.network/perun-ckb-backend/channel/adjudicator" "perun.network/perun-ckb-backend/channel/asset" "perun.network/perun-ckb-backend/channel/funder" @@ -45,8 +44,8 @@ type PaymentClient struct { Name string balance *big.Int sudtBalance *big.Int - Account *wallet.Account - wAddr wire.Address + walletAccs map[gpwallet.BackendID]gpwallet.Account + wireAddrs map[gpwallet.BackendID]wire.Address Network types.Network PerunClient *client.Client net *p2p.Net @@ -59,10 +58,9 @@ func NewPaymentClient( network types.Network, deployment backend.Deployment, rpcUrl string, - account *wallet.Account, + walletAcc *wallet.Account, key secp256k1.PrivateKey, wallet *wallet.EphemeralWallet, - persistRestorer persistence.PersistRestorer, wAddr wire.Address, net *p2p.Net, @@ -71,7 +69,7 @@ func NewPaymentClient( if err != nil { return nil, err } - signer := backend.NewSignerInstance(address.AsParticipant(account.Address()).ToCKBAddress(network), key, network) + signer := backend.NewSignerInstance(address.AsParticipant(walletAcc.Address()).ToCKBAddress(network), key, network) ckbClient, err := ckbclient.NewClient(backendRPCClient, *signer, deployment) if err != nil { @@ -84,11 +82,18 @@ func NewPaymentClient( return nil, err } - perunClient, err := client.New(wAddr, net.Bus, f, a, wallet, watcher) + waddresses := map[gpwallet.BackendID]wire.Address{channel.CKBBackendID: wAddr} + wallets := map[gpwallet.BackendID]gpwallet.Wallet{ + channel.CKBBackendID: wallet, + } + walletAccs := map[gpwallet.BackendID]gpwallet.Account{ + channel.CKBBackendID: walletAcc, + } + + perunClient, err := client.New(waddresses, net.Bus, f, a, wallets, watcher) if err != nil { return nil, err } - perunClient.EnablePersistence(persistRestorer) balanceRPC, err := rpc.Dial(rpcUrl) if err != nil { @@ -98,8 +103,8 @@ func NewPaymentClient( Name: name, balance: big.NewInt(0), sudtBalance: big.NewInt(0), - Account: account, - wAddr: wAddr, + walletAccs: walletAccs, + wireAddrs: waddresses, Network: network, PerunClient: perunClient, channels: make(chan *PaymentChannel, 1), @@ -112,16 +117,20 @@ func NewPaymentClient( } // WalletAddress returns the wallet address of the client. -func (p *PaymentClient) WalletAddress() gpwallet.Address { - return p.Account.Address() +func (p *PaymentClient) WalletAddress() map[gpwallet.BackendID]gpwallet.Address { + addresses := make(map[gpwallet.BackendID]gpwallet.Address, len(p.walletAccs)) + for backendID, acc := range p.walletAccs { + addresses[backendID] = acc.Address() + } + return addresses } -func (p *PaymentClient) WireAddress() wire.Address { - return p.wAddr +func (p *PaymentClient) WireAddress() map[gpwallet.BackendID]wire.Address { + return p.wireAddrs } func (p *PaymentClient) PeerID() string { - walletAddr := p.wAddr.(*p2p.Address) + walletAddr := p.wireAddrs[channel.CKBBackendID].(*p2p.Address) return walletAddr.ID.String() } @@ -138,22 +147,24 @@ func (p *PaymentClient) GetBalances() string { } // OpenChannel opens a new channel with the specified peer and funding. -func (p *PaymentClient) OpenChannel(peer wire.Address, peerID string, amounts map[gpchannel.Asset]float64) *PaymentChannel { +func (p *PaymentClient) OpenChannel(peer map[gpwallet.BackendID]wire.Address, peerID string, amounts map[gpchannel.Asset]float64) *PaymentChannel { // We define the channel participants. The proposer always has index 0. Here // we use the on-chain addresses as off-chain addresses, but we could also // use different ones. - participants := []wire.Address{p.WireAddress(), peer} + participants := []map[gpwallet.BackendID]wire.Address{p.WireAddress(), peer} p.net.Dialer.Register(peer, peerID) assets := make([]gpchannel.Asset, len(amounts)) + backends := make([]gpwallet.BackendID, len(amounts)) i := 0 for a := range amounts { assets[i] = a + backends[i] = channel.CKBBackendID i++ } // We create an initial allocation which defines the starting balances. - initAlloc := gpchannel.NewAllocation(2, assets...) + initAlloc := gpchannel.NewAllocation(2, backends, assets...) for a, amount := range amounts { switch a := a.(type) { case *asset.Asset: @@ -179,7 +190,7 @@ func (p *PaymentClient) OpenChannel(peer wire.Address, peerID string, amounts ma challengeDuration := uint64(10) // On-chain challenge duration in seconds. proposal, err := client.NewLedgerChannelProposal( challengeDuration, - p.Account.Address(), + p.WalletAddress(), initAlloc, participants, ) @@ -216,29 +227,3 @@ func (p *PaymentClient) AcceptedChannel() *PaymentChannel { func (p *PaymentClient) Shutdown() { p.PerunClient.Close() } - -func (c *PaymentClient) Restore(peer wire.Address, peerID string) []*PaymentChannel { - var restoredChannels []*client.Channel - //c.net.Dialer.Register(peer, peerID) - //TODO: Remove this hack. Find why asset is not found upon restoring - c.PerunClient.OnNewChannel(func(ch *client.Channel) { - restoredChannels = append(restoredChannels, ch) - }) - - err := c.PerunClient.Restore(context.TODO()) - if err != nil { - fmt.Println("Error restoring channels") - } - - paymentChannels := make([]*PaymentChannel, len(restoredChannels)) - assets := make([]channel.Asset, 1) - assets = append(assets, &asset.Asset{ - IsCKBytes: true, - SUDT: nil, - }) - for i, ch := range restoredChannels { - paymentChannels[i] = newPaymentChannel(ch, assets) - } - - return paymentChannels -} diff --git a/payment-channel-ckb/client/handle.go b/payment-channel-ckb/client/handle.go index 4c1e932..91bc792 100644 --- a/payment-channel-ckb/client/handle.go +++ b/payment-channel-ckb/client/handle.go @@ -21,6 +21,7 @@ import ( "perun.network/go-perun/channel" "perun.network/go-perun/client" + ckbchannel "perun.network/perun-ckb-backend/channel" ) // HandleProposal is the callback for incoming channel proposals. @@ -102,5 +103,5 @@ func (p *PaymentClient) HandleUpdate(cur *channel.State, next client.ChannelUpda // HandleAdjudicatorEvent is the callback for smart contract events. func (p *PaymentClient) HandleAdjudicatorEvent(e channel.AdjudicatorEvent) { - log.Printf("Adjudicator event: type = %T, client = %v", e, p.Account) + log.Printf("Adjudicator event: type = %T, client = %v", e, p.WalletAddress()[ckbchannel.CKBBackendID]) } diff --git a/payment-channel-ckb/deployment/deployment.go b/payment-channel-ckb/deployment/deployment.go index dbc89dc..17ba6ca 100644 --- a/payment-channel-ckb/deployment/deployment.go +++ b/payment-channel-ckb/deployment/deployment.go @@ -1,17 +1,3 @@ -// Copyright 2024 PolyCrypt GmbH -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package deployment import ( @@ -19,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "log" "os" "path" "strings" @@ -46,22 +33,32 @@ type Migration struct { DepGroupRecipes []interface{} `json:"dep_group_recipes"` } -func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) { - pcts := m.CellRecipes[0] +func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg string, vcm Migration) (backend.Deployment, SUDTInfo, error) { + sudtInfo, err := m.GetSUDT() + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + pcts := m.CellRecipes[1] if pcts.Name != "pcts" { - return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("first cell recipe must be pcts") + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("second cell recipe must be pcts") } - pcls := m.CellRecipes[1] + pcls := m.CellRecipes[2] if pcls.Name != "pcls" { - return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("second cell recipe must be pcls") + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("third cell recipe must be pcls") } - pfls := m.CellRecipes[2] + pfls := m.CellRecipes[3] if pfls.Name != "pfls" { - return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("third cell recipe must be pfls") + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("fourth cell recipe must be pfls") } - sudtInfo, err := m.GetSUDT() - if err != nil { - return backend.Deployment{}, SUDTInfo{}, err + + // Virtual channel scripts. + vcts := vcm.CellRecipes[0] + if vcts.Name != "vcts" { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("fifth cell recipe must be vcts") + } + vcls := vcm.CellRecipes[1] + if vcls.Name != "vcls" { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("sixth cell recipe must be vcls") } // NOTE: The SUDT lock-arg always contains a newline character at the end. hexString := strings.ReplaceAll(sudtOwnerLockArg[2:], "\n", "") @@ -77,21 +74,35 @@ func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg PCTSDep: types.CellDep{ OutPoint: &types.OutPoint{ TxHash: types.HexToHash(pcts.TxHash), - Index: m.CellRecipes[0].Index, + Index: pcts.Index, }, DepType: types.DepTypeCode, }, PCLSDep: types.CellDep{ OutPoint: &types.OutPoint{ TxHash: types.HexToHash(pcls.TxHash), - Index: m.CellRecipes[0].Index, + Index: pcls.Index, + }, + DepType: types.DepTypeCode, + }, + VCTSDep: types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(vcts.TxHash), + Index: vcts.Index, + }, + DepType: types.DepTypeCode, + }, + VCLSDep: types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(vcls.TxHash), + Index: vcls.Index, }, DepType: types.DepTypeCode, }, PFLSDep: types.CellDep{ OutPoint: &types.OutPoint{ TxHash: types.HexToHash(pfls.TxHash), - Index: m.CellRecipes[0].Index, + Index: pfls.Index, }, DepType: types.DepTypeCode, }, @@ -99,6 +110,10 @@ func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg PCTSHashType: types.HashTypeData1, PCLSCodeHash: types.HexToHash(pcls.DataHash), PCLSHashType: types.HashTypeData1, + VCTSCodeHash: types.HexToHash(vcts.DataHash), + VCTSHashType: types.HashTypeData1, + VCLSCodeHash: types.HexToHash(vcls.DataHash), + VCLSHashType: types.HashTypeData1, PFLSCodeHash: types.HexToHash(pfls.DataHash), PFLSHashType: types.HashTypeData1, PFLSMinCapacity: PFLSMinCapacity, @@ -118,9 +133,9 @@ func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg } func (m Migration) GetSUDT() (*SUDTInfo, error) { - sudt := m.CellRecipes[3] + sudt := m.CellRecipes[0] if sudt.Name != "sudt" { - return nil, fmt.Errorf("fourth cell recipe must be sudt") + return nil, fmt.Errorf("first cell recipe must be sudt") } sudtScript := types.Script{ @@ -141,7 +156,7 @@ func (m Migration) GetSUDT() (*SUDTInfo, error) { }, nil } -func GetDeployment(migrationDir, systemScriptsDir, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) { +func GetDeployment(migrationDir, migrationDirVC, systemScriptsDir, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) { dir, err := os.ReadDir(migrationDir) if err != nil { return backend.Deployment{}, SUDTInfo{}, err @@ -149,12 +164,38 @@ func GetDeployment(migrationDir, systemScriptsDir, sudtOwnerLockArg string) (bac if len(dir) != 1 { return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("migration dir must contain exactly one file") } + + vc_dir, err := os.ReadDir(migrationDirVC) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + if len(vc_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() + defer func() { + if err := migrationFile.Close(); err != nil { + log.Fatalf("failed to close migration file: %v\n", err) + } + }() + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + + vcMigrationName := vc_dir[0].Name() + vcMigrationFile, err := os.Open(path.Join(migrationDirVC, vcMigrationName)) + defer func() { + if err := vcMigrationFile.Close(); err != nil { + log.Fatalf("failed to close vc migration file: %v\n", err) + } + }() if err != nil { return backend.Deployment{}, SUDTInfo{}, err } + + // Read and unmarshall migration file migrationData, err := io.ReadAll(migrationFile) if err != nil { return backend.Deployment{}, SUDTInfo{}, err @@ -165,9 +206,23 @@ func GetDeployment(migrationDir, systemScriptsDir, sudtOwnerLockArg string) (bac return backend.Deployment{}, SUDTInfo{}, err } + // Read and unmarshall vc migration file + vcMigrationData, err := io.ReadAll(vcMigrationFile) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + var vcMigration Migration + err = json.Unmarshal(vcMigrationData, &vcMigration) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + + // Read system scripts ss, err := GetSystemScripts(systemScriptsDir) if err != nil { return backend.Deployment{}, SUDTInfo{}, err } - return migration.MakeDeployment(ss, sudtOwnerLockArg) + fmt.Printf("Migration: %v\n", migration) + fmt.Printf("VC Migration: %v\n", vcMigration) + return migration.MakeDeployment(ss, sudtOwnerLockArg, vcMigration) } diff --git a/payment-channel-ckb/devnet/contracts/.cargo/config.toml b/payment-channel-ckb/devnet/contracts/.cargo/config.toml new file mode 100644 index 0000000..f4108c7 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.riscv64imac-unknown-none-elf] +linker = "rust-lld" +rustflags = ["-C", "linker=rust-lld"] + +[build] +target = "x86_64-unknown-linux-gnu" \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml b/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml index 948acce..49a0113 100644 --- a/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml +++ b/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml @@ -5,18 +5,18 @@ on: branches: [ "dev" ] pull_request: branches: [ "dev" ] + workflow_dispatch: env: CARGO_TERM_COLOR: always jobs: build: - runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.cargo/registry @@ -24,15 +24,37 @@ jobs: target tests/target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Capsule - run: cargo install --version 0.9.2 ckb-capsule - - name: Build perun-common - run: cargo build - working-directory: contracts/perun-common - - name: Test perun-common - run: cargo test - working-directory: contracts/perun-common + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y gcc-riscv64-unknown-elf binutils-riscv64-unknown-elf libc6-dev-riscv64-cross libc6-riscv64-cross linux-libc-dev-riscv64-cross + wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 18 && rm llvm.sh + cargo install cargo-generate + rustup target add riscv64imac-unknown-none-elf + - name: Create Symlink + run: sudo ln -s /usr/riscv64-linux-gnu/include/gnu/stubs-lp64d.h /usr/riscv64-linux-gnu/include/gnu/stubs-lp64.h - name: Build contracts - run: capsule build + env: + RUSTFLAGS: "-C linker=rust-lld" + CARGO_TARGET_RISCV64IMAC_UNKNOWN_NONE_ELF_LINKER: rust-lld + CC_riscv64imac_unknown_none_elf: riscv64-unknown-elf-gcc + AR_riscv64imac_unknown_none_elf: riscv64-unknown-elf-ar + C_INCLUDE_PATH: /usr/riscv64-linux-gnu/include + CFLAGS: "-I/usr/riscv64-linux-gnu/include" + TARGET_CFLAGS: "-I/usr/riscv64-linux-gnu/include" + run: | + chmod +x ./setup_env.sh + source ./setup_env.sh build && make build + - name: Test contracts - run: capsule test + env: + RUSTFLAGS: "-C linker=rust-lld" + CARGO_TARGET_RISCV64IMAC_UNKNOWN_NONE_ELF_LINKER: rust-lld + CC_riscv64imac_unknown_none_elf: riscv64-unknown-elf-gcc + AR_riscv64imac_unknown_none_elf: riscv64-unknown-elf-ar + C_INCLUDE_PATH: /usr/riscv64-linux-gnu/include + CFLAGS: "-I/usr/riscv64-linux-gnu/include" + TARGET_CFLAGS: "-I/usr/riscv64-linux-gnu/include" + run: | + source ./setup_env.sh test && make test diff --git a/payment-channel-ckb/devnet/contracts/.gitignore b/payment-channel-ckb/devnet/contracts/.gitignore deleted file mode 100644 index 8ce9103..0000000 --- a/payment-channel-ckb/devnet/contracts/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Rust -target/* -.cache/.cargo/* -contracts/**/target/* -tests/target/* -migrations/** - -# C -contracts/c/build/* - -# others -build/* -!.gitkeep -.tmp/ diff --git a/payment-channel-ckb/devnet/contracts/Cargo.lock b/payment-channel-ckb/devnet/contracts/Cargo.lock index d54baf9..0dfe61d 100644 --- a/payment-channel-ckb/devnet/contracts/Cargo.lock +++ b/payment-channel-ckb/devnet/contracts/Cargo.lock @@ -1,18 +1,77 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] [[package]] name = "base16ct" -version = "0.1.1" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bit-vec" @@ -20,11 +79,39 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + [[package]] name = "blake2b-ref" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95916998c798756098a4eb1b3f2cd510659705a9817bf203d61abd30fbec3e7b" +checksum = "294d17c72e0ba59fad763caa112368d0672083779cdebbb97164f4bb4c1e339a" [[package]] name = "blake2b-rs" @@ -45,26 +132,77 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.11.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94" +dependencies = [ + "hybrid-array", +] + [[package]] name = "buddy-alloc" -version = "0.4.2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee741d62dcaf41ca303576ef890989ccb01d5dd77f8ce1a6d6c7846ab5d09efb" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "cacache" +version = "13.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "5c5063741c7b2e260bbede781cf4679632dd90e2718e99f7715e46824b65670b" dependencies = [ + "digest 0.10.7", + "either", + "futures", + "hex", + "libc", + "memmap2", + "miette", + "reflink-copy", "serde", + "serde_derive", + "serde_json", + "sha1", + "sha2", + "ssri", + "tempfile", + "thiserror", + "tokio", + "tokio-stream", + "walkdir", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -72,32 +210,104 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ckb-always-success-script" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3b72a38c9920a29990df12002c4d069a147c8782f0c211f8a01b2df8f42bfd" + +[[package]] +name = "ckb-chain-spec" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c805be1e6fc1b82cdd86d3ddb2e110c7afac38d3a0484c9ce364ad0c161692" +dependencies = [ + "cacache", + "ckb-constant", + "ckb-crypto", + "ckb-dao-utils", + "ckb-error", + "ckb-hash 0.200.0", + "ckb-jsonrpc-types", + "ckb-logger", + "ckb-pow", + "ckb-rational", + "ckb-resource", + "ckb-traits", + "ckb-types", + "serde", + "toml", +] + [[package]] name = "ckb-channel" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920f26cc48cadcaf6f7bcc3960fde9f9f355633b6361da8ef31e1e1c00fc8858" +checksum = "d01c19d4cd17c7dade4e17470bf4c9383ca11f1ea1e17cb65075eb62663b67e3" dependencies = [ "crossbeam-channel", ] +[[package]] +name = "ckb-constant" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "946c260892eee2bead85705be334f871076f15724cb4f69d0a43701899e45cb8" + +[[package]] +name = "ckb-crypto" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a129a43e971a187c62060e7beb4d7077727d6fd6871f3ac1890653b8b67644c" +dependencies = [ + "ckb-fixed-hash", + "faster-hex", + "rand 0.8.5", + "secp256k1", + "thiserror", +] + +[[package]] +name = "ckb-dao" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1029eb303cd5fa2772ba6a7628b420759a76447ddfec0dfb5b8cd8568f0106e7" +dependencies = [ + "byteorder", + "ckb-chain-spec", + "ckb-dao-utils", + "ckb-traits", + "ckb-types", +] + +[[package]] +name = "ckb-dao-utils" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14af6d9a76099ce2a50712eb3639e483f034ad94ed74ff778e43aeda74d26ac" +dependencies = [ + "byteorder", + "ckb-error", + "ckb-types", +] + [[package]] name = "ckb-error" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446a519d8a847d97f1c8ece739dc1748751a9a2179249c96c45cced0825a7aa5" +checksum = "80333cbe31b5a8c9dbdd381a9baab5903f8f502c379c7208d44a19f429054dc2" dependencies = [ "anyhow", "ckb-occupied-capacity", - "derive_more", + "derive_more 1.0.0", "thiserror", ] [[package]] name = "ckb-fixed-hash" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00cbbc455b23748b32e06d16628a03e30d56ffa057f17093fdf5b42d4fb6c879" +checksum = "e6bbcb0643a3e983cdc2a75bd4a84746103a622490c0d08256ab9a97c12d8b27" dependencies = [ "ckb-fixed-hash-core", "ckb-fixed-hash-macros", @@ -105,10 +315,11 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-core" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e644a4e026625b4be5a04cdf6c02043080e79feaf77d9cdbb2f0e6553f751" +checksum = "230aba1d073a0cc4ec9b0b74a9f166020ebaad439b5e4dd4518606a20cd94661" dependencies = [ + "ckb_schemars", "faster-hex", "serde", "thiserror", @@ -116,9 +327,9 @@ dependencies = [ [[package]] name = "ckb-fixed-hash-macros" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cfc980ef88c217825172eb46df269f47890f5e78a38214416f13b3bd17a4b4" +checksum = "5a4f59e054081f9955fb9059736a1e4ff4fc6f1e29ad894a9caaa2c78d5cb574" dependencies = [ "ckb-fixed-hash-core", "proc-macro2", @@ -126,16 +337,73 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ckb-gen-types" +version = "0.119.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc221d4b9d6d39215b1d62be855861b8b0c8d668ca29874903b0bf5d0b4d9fa" +dependencies = [ + "cfg-if", + "ckb-hash 0.119.0", + "molecule", +] + +[[package]] +name = "ckb-gen-types" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8b9b56ee90afca6710a512abac5c4d7dba69b39b63ed9c246ec17aee764bf8" +dependencies = [ + "cfg-if", + "ckb-error", + "ckb-fixed-hash", + "ckb-hash 0.200.0", + "ckb-occupied-capacity", + "molecule", + "numext-fixed-uint", +] + +[[package]] +name = "ckb-hash" +version = "0.119.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ba7c72f86f239b3e0154f51d6cd5d0d83bbaa8775fdc7b6bcac459ae24b6fd" +dependencies = [ + "blake2b-ref", +] + [[package]] name = "ckb-hash" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d9b683e89ae4ffdd5aaf4172eab00b6bbe7ea24e2abf77d3eb850ba36e8983" +checksum = "93571b17af91fc16f03275bd70612e16092ad4d2e89eaed9cdf513cd3f1e20e7" dependencies = [ "blake2b-ref", "blake2b-rs", ] +[[package]] +name = "ckb-jsonrpc-types" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fa22c16f8b2ea5f97a9caade99c0cb21e339d7b0a01f7262682fe434156c8b" +dependencies = [ + "ckb-types", + "ckb_schemars", + "faster-hex", + "serde", + "serde_json", +] + +[[package]] +name = "ckb-logger" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1386124f2e4742eccb7ab85922e55eae3a5574b77ebf7d0cd943204b92a2397" +dependencies = [ + "log", +] + [[package]] name = "ckb-merkle-mountain-range" version = "0.5.2" @@ -145,11 +413,23 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ckb-mock-tx-types" +version = "0.200.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66b034f2767462be3daf0dff4d5d404538dcd9c2d6d3da0b1915a8f8cedb9d6" +dependencies = [ + "ckb-jsonrpc-types", + "ckb-traits", + "ckb-types", + "serde", +] + [[package]] name = "ckb-occupied-capacity" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2a1dd0d4ba5dafba1e30d437c1148b20f42edb76b6794323e05bda626754eb" +checksum = "e0e8200ffb81ab6296944c408bf26bafa708e50f864138da8ccd888e9988c632" dependencies = [ "ckb-occupied-capacity-core", "ckb-occupied-capacity-macros", @@ -157,18 +437,18 @@ dependencies = [ [[package]] name = "ckb-occupied-capacity-core" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ebba3d564098a84c83f4740e1dce48a5e2da759becdb47e3c7965f0808e6e92" +checksum = "1b35c451084252f1471acbe06284363fa9bcce1367b4fa31ac18ac0df0ea269f" dependencies = [ "serde", ] [[package]] name = "ckb-occupied-capacity-macros" -version = "0.108.0" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6321bba85cdf9724029d8c906851dd4a90906869b42f9100b16645a1261d4c" +checksum = "c1a08d40765806c534aa4e55dd73b17c6c30edfc86c266e83bd37b7349dd2fbf" dependencies = [ "ckb-occupied-capacity-core", "quote", @@ -176,184 +456,464 @@ dependencies = [ ] [[package]] -name = "ckb-rational" -version = "0.108.0" +name = "ckb-pow" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2519249f8d47fa758d3fb3cf3049327c69ce0f2acd79d61427482c8661d3dbd" +checksum = "656ce99ec57ed75be3d87800d747c15311a99acd24f8d332ecf9aad99dcd4fd0" dependencies = [ - "numext-fixed-uint", + "byteorder", + "ckb-hash 0.200.0", + "ckb-types", + "eaglesong", + "log", "serde", ] [[package]] -name = "ckb-standalone-types" -version = "0.1.2" +name = "ckb-rational" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22d7cbbdab96e6b809a102cf88bfec28795a0a3c06bfdea4abe4de89777801cd" +checksum = "4224693f82c2380a319efc4841b29d90726a765b50776ae7fd66a5537d762ab8" dependencies = [ - "cfg-if", - "molecule", + "numext-fixed-uint", + "serde", ] [[package]] -name = "ckb-std" -version = "0.10.0" +name = "ckb-resource" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a6ad40455c446ad6fbb303dae24827fc309f43558f59d1f1b863a9de3e9f81" +checksum = "9e1df21747b7784762521a7375935c229dd5cc5f555f5f020e57152840134142" dependencies = [ - "buddy-alloc", - "cc", - "ckb-standalone-types", - "cstr_core", + "ckb-system-scripts", + "ckb-types", + "includedir", + "includedir_codegen", + "phf", + "serde", + "walkdir", ] [[package]] -name = "ckb-types" -version = "0.108.0" +name = "ckb-script" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c22b3b1ca8f88a8f48e2f73321c0605281c9c6f1e1c4d651c6138265c22291e" +checksum = "fb478be8097919c929d8595310ed37f7a2359d7b3a2b1ec269d68794cb2a44c1" dependencies = [ - "bit-vec", - "bytes", - "ckb-channel", + "byteorder", + "ckb-chain-spec", "ckb-error", - "ckb-fixed-hash", - "ckb-hash", - "ckb-merkle-mountain-range", - "ckb-occupied-capacity", - "ckb-rational", - "derive_more", - "merkle-cbt", - "molecule", - "numext-fixed-uint", - "once_cell", + "ckb-hash 0.200.0", + "ckb-logger", + "ckb-traits", + "ckb-types", + "ckb-vm", + "faster-hex", + "serde", + "tokio", ] [[package]] -name = "const-oid" -version = "0.9.2" +name = "ckb-std" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "4a673595baadfa1712ff03a36e1519f28015cf9944282410863d5e256336f5b9" +dependencies = [ + "buddy-alloc", + "cc", + "ckb-gen-types 0.119.0", + "gcd", +] [[package]] -name = "cpufeatures" -version = "0.2.6" +name = "ckb-std" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "d399a77aef9814044db51bfd61a4aaa42ee468bfb9a13e83ba656bd95f7793ca" dependencies = [ - "libc", + "buddy-alloc", + "cc", + "ckb-gen-types 0.200.0", + "ckb-x64-simulator", + "gcd", ] [[package]] -name = "crossbeam-channel" -version = "0.5.8" +name = "ckb-system-scripts" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "fa5c59063142de7a68cfad4449c6b3863563856219a2925dfb8c5f019ec2aa47" dependencies = [ - "cfg-if", - "crossbeam-utils", + "blake2b-rs", + "faster-hex", + "includedir", + "includedir_codegen", + "phf", ] [[package]] -name = "crossbeam-utils" -version = "0.8.15" +name = "ckb-systemtime" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "def6e0911ec086f0d4886257e29ce0ea8c1640ddc9953ccaa8421070c724a524" dependencies = [ - "cfg-if", + "web-time", ] [[package]] -name = "crypto-bigint" -version = "0.4.9" +name = "ckb-testtool" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +checksum = "8b8e8d6fbb0efa9575905add21e788d65a48ae270ec9c19dbb6ee73b689b8ab2" dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", + "ckb-always-success-script", + "ckb-chain-spec", + "ckb-crypto", + "ckb-error", + "ckb-hash 0.200.0", + "ckb-jsonrpc-types", + "ckb-mock-tx-types", + "ckb-resource", + "ckb-script", + "ckb-traits", + "ckb-types", + "ckb-verification", + "faster-hex", + "lazy_static", + "libloading", + "rand 0.8.5", + "serde_json", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "ckb-traits" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "19e1ea54ff280b7167818ed7ec05a1e03d8a27ea086d1057c4a505b6781a958f" dependencies = [ - "generic-array", - "typenum", + "ckb-types", ] [[package]] -name = "cstr_core" -version = "0.2.6" +name = "ckb-types" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" +checksum = "5d31954ae56109ea088572bad1c194ac0ed709f7fd7fd01dfcf338f864699cad" dependencies = [ - "cty", - "memchr", + "bit-vec", + "bytes", + "ckb-channel", + "ckb-constant", + "ckb-error", + "ckb-fixed-hash", + "ckb-gen-types 0.200.0", + "ckb-hash 0.200.0", + "ckb-merkle-mountain-range", + "ckb-occupied-capacity", + "ckb-rational", + "derive_more 1.0.0", + "golomb-coded-set", + "merkle-cbt", + "molecule", + "numext-fixed-uint", + "paste", ] [[package]] -name = "cty" -version = "0.2.2" +name = "ckb-verification" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +checksum = "20135adeba292d9695fd6c056406c289ecd092f20a67f145221201b58cd4217f" +dependencies = [ + "ckb-chain-spec", + "ckb-dao", + "ckb-dao-utils", + "ckb-error", + "ckb-pow", + "ckb-script", + "ckb-systemtime", + "ckb-traits", + "ckb-types", + "ckb-verification-traits", + "derive_more 1.0.0", + "lru", + "tokio", +] [[package]] -name = "der" -version = "0.6.1" +name = "ckb-verification-traits" +version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +checksum = "89f161e12be27442602003fd333c31008b1b54dd323ba6f3e6a502a9dccb6415" dependencies = [ - "const-oid", + "bitflags 1.3.2", + "ckb-error", ] [[package]] -name = "derive_more" -version = "0.99.17" +name = "ckb-vm" +version = "0.24.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "49dc9651f4fe97dc45fcbc9d5b35f1e2d66accbab6d78f847d3000336aec4dbf" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "byteorder", + "bytes", + "cc", + "ckb-vm-definitions", + "derive_more 0.99.19", + "goblin 0.2.3", + "goblin 0.4.0", + "rand 0.7.3", + "scroll", + "serde", ] [[package]] -name = "digest" -version = "0.10.6" +name = "ckb-vm-definitions" +version = "0.24.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "95db407ba457416941e70dbaa28fb546d94a4f55be623316d24fb750320b1f45" dependencies = [ - "block-buffer", - "crypto-common", - "subtle", + "paste", ] +[[package]] +name = "ckb-x64-simulator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdf527e21bda1003b49f71533a1f2db8780e151ae518916763e133514a0f5c7" +dependencies = [ + "cc", + "ckb-mock-tx-types", + "ckb-types", + "faster-hex", + "lazy_static", + "libc", + "libloading", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "ckb_schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c37520aaae28169f4b29cd754f414d01ef32b8209c85d4473bc89d760250b990" +dependencies = [ + "ckb_schemars_derive", + "dyn-clone", + "serde", + "serde_json", +] + +[[package]] +name = "ckb_schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1506d63311ded0645342c052b1eb21ba272177b32f55d8eb7e11255aed3e74c6" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.100", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b" +dependencies = [ + "block-buffer 0.11.0-rc.4", + "const-oid 0.10.1", + "crypto-common 0.2.0-rc.3", +] + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "eaglesong" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d978bd5d343e8ab9b5c0fc8d93ff9c602fdc96616ffff9c05ac7a155419b824" + [[package]] name = "ecdsa" -version = "0.14.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", + "digest 0.10.7", "elliptic-curve", "rfc6979", "signature", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "elliptic-curve" -version = "0.12.3" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "der", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -363,22 +923,143 @@ dependencies = [ "zeroize", ] +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "faster-hex" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "ff" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", "subtle", ] +[[package]] +name = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "generic-array" version = "0.14.7" @@ -387,6 +1068,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -397,20 +1079,89 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "goblin" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "goblin" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532a09cd3df2c6bbfc795fb0434bff8f22255d1d07328180e918a2e6ce122d4d" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "golomb-coded-set" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f314a99fb5b7f0f9d0a8388539578f83f3aca6a65f588b8dbeefb731e2f98" +dependencies = [ + "siphasher", ] [[package]] name = "group" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + [[package]] name = "heapsize" version = "0.4.2" @@ -421,422 +1172,1311 @@ dependencies = [ ] [[package]] -name = "hmac" -version = "0.12.1" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hybrid-array" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af" +dependencies = [ + "typenum", +] + +[[package]] +name = "includedir" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afd126bd778c00c43a9dc76d1609a0894bf4222088088b2217ccc0ce9e816db7" +dependencies = [ + "flate2", + "phf", +] + +[[package]] +name = "includedir_codegen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ac1500c9780957c9808c4ec3b94002f35aab01483833f5a8bce7dfb243e3148" +dependencies = [ + "flate2", + "phf_codegen", + "walkdir", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ - "digest", + "once_cell", + "wasm-bindgen", ] [[package]] name = "k256" -version = "0.11.6" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", "sha2", +] + +[[package]] +name = "keccak" +version = "0.2.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cdd4f0dc5807b9a2b25dd48a3f58e862606fe7bd47f41ecde36e97422d7e90" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "merkle-cbt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171d2f700835121c3b04ccf0880882987a050fd5c7ae88148abf537d33dd3a56" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", +] + +[[package]] +name = "molecule" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6efe1c7efcd0bdf4ca590e104bcb13087d9968956ae4ae98e92fb8c1da0f3730" +dependencies = [ + "bytes", + "cfg-if", + "faster-hex", +] + +[[package]] +name = "numext-constructor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621fe0f044729f810c6815cdd77e8f5e0cd803ce4f6a38380ebfc1322af98661" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "numext-fixed-uint" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c68c76f96d589d1009a666c5072f37f3114d682696505f2cf445f27766c7d70" +dependencies = [ + "numext-fixed-uint-core", + "numext-fixed-uint-hack", +] + +[[package]] +name = "numext-fixed-uint-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aab1d6457b97b49482f22a92f0f58a2f39bdd7f3b2f977eae67e8bc206aa980" +dependencies = [ + "heapsize", + "numext-constructor", + "rand 0.7.3", + "serde", + "thiserror", +] + +[[package]] +name = "numext-fixed-uint-hack" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200f8d55c36ec1b6a8cf810115be85d4814f045e0097dfd50033ba25adb4c9e" +dependencies = [ + "numext-fixed-uint-core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "perun-channel-lockscript" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "perun-channel-typescript" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "perun-common" +version = "0.1.0" +dependencies = [ + "blake2b-rs", + "buddy-alloc", + "ckb-gen-types 0.200.0", + "ckb-occupied-capacity", + "ckb-std 0.17.2", + "ckb-types", + "k256", + "molecule", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", "sha3", ] [[package]] -name = "keccak" -version = "0.1.3" +name = "perun-funds-lockscript" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "perun-vchannel-lockscript" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "perun-vchannel-typescript" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared", + "rand 0.7.3", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "reflink-copy" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b86038e146b9a61557e1a2e58cdf2eddc0b46ce141b55541b1c1b9f3189d618" +dependencies = [ + "cfg-if", + "libc", + "rustix", + "windows", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sample-udt" +version = "0.1.0" +dependencies = [ + "bytes", + "ckb-std 0.17.2", + "molecule", + "perun-common", +] + +[[package]] +name = "scroll" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e6a92fd180fd205defdc0b78288ce847c7309d329fd6647a814567e67db50e" +dependencies = [ + "digest 0.11.0-rc.0", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ssri" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" +dependencies = [ + "base64", + "digest 0.10.7", + "hex", + "miette", + "serde", + "sha-1", + "sha2", + "thiserror", + "xxhash-rust", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" dependencies = [ - "cpufeatures", + "fastrand", + "getrandom 0.3.2", + "once_cell", + "rustix", + "windows-sys", ] [[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +name = "tests" +version = "0.1.0" +dependencies = [ + "ckb-gen-types 0.200.0", + "ckb-occupied-capacity", + "ckb-std 0.16.4", + "ckb-testtool", + "hex", + "k256", + "molecule", + "perun-common", + "rand 0.9.0", + "rand_core 0.6.4", + "serde_json", +] [[package]] -name = "memchr" -version = "2.5.0" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] [[package]] -name = "merkle-cbt" -version = "0.3.2" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171d2f700835121c3b04ccf0880882987a050fd5c7ae88148abf537d33dd3a56" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] -name = "molecule" -version = "0.7.3" +name = "tokio" +version = "1.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc8276c02a006bddad7d1c28c1a88f30421e1b5f0ba0ca96ceb8077c7d20c01" +checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ + "backtrace", "bytes", - "cfg-if", - "faster-hex", + "pin-project-lite", + "tokio-macros", ] [[package]] -name = "numext-constructor" -version = "0.1.6" +name = "tokio-macros" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "621fe0f044729f810c6815cdd77e8f5e0cd803ce4f6a38380ebfc1322af98661" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.100", ] [[package]] -name = "numext-fixed-uint" -version = "0.1.6" +name = "tokio-stream" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c68c76f96d589d1009a666c5072f37f3114d682696505f2cf445f27766c7d70" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ - "numext-fixed-uint-core", - "numext-fixed-uint-hack", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "numext-fixed-uint-core" -version = "0.1.6" +name = "toml" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aab1d6457b97b49482f22a92f0f58a2f39bdd7f3b2f977eae67e8bc206aa980" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "heapsize", - "numext-constructor", - "rand", "serde", - "thiserror", ] [[package]] -name = "numext-fixed-uint-hack" -version = "0.1.6" +name = "typenum" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200f8d55c36ec1b6a8cf810115be85d4814f045e0097dfd50033ba25adb4c9e" -dependencies = [ - "numext-fixed-uint-core", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] -name = "once_cell" -version = "1.17.1" +name = "unicode-ident" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "perun-channel-lockscript" -version = "0.1.0" -dependencies = [ - "ckb-std", - "perun-common", -] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] -name = "perun-channel-typescript" -version = "0.1.0" -dependencies = [ - "ckb-std", - "perun-common", -] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "perun-common" -version = "0.1.0" -dependencies = [ - "blake2b-rs", - "buddy-alloc", - "ckb-occupied-capacity", - "ckb-standalone-types", - "ckb-std", - "ckb-types", - "k256", - "molecule", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "perun-funds-lockscript" -version = "0.1.0" +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "ckb-std", - "perun-common", + "same-file", + "winapi-util", ] [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] -name = "proc-macro2" -version = "1.0.56" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ - "unicode-ident", + "wit-bindgen-rt", ] [[package]] -name = "quote" -version = "1.0.26" +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ + "bumpalo", + "log", "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-shared", ] [[package]] -name = "rand" -version = "0.7.3" +name = "wasm-bindgen-macro" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ - "getrandom", - "libc", - "rand_chacha", - "rand_core 0.5.1", - "rand_hc", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "rand_chacha" -version = "0.2.2" +name = "wasm-bindgen-macro-support" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "wasm-bindgen-shared" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ - "getrandom", + "unicode-ident", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "rand_core 0.5.1", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "rfc6979" -version = "0.3.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", + "windows-sys", ] [[package]] -name = "rustc-std-workspace-alloc" -version = "1.0.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "rustc-std-workspace-core" -version = "1.0.0" +name = "windows" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" +checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] [[package]] -name = "sample-udt" -version = "0.1.0" +name = "windows-collections" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" dependencies = [ - "ckb-std", - "perun-common", + "windows-core", ] [[package]] -name = "sec1" -version = "0.3.0" +name = "windows-core" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" dependencies = [ - "base16ct", - "der", - "generic-array", - "subtle", - "zeroize", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "serde" -version = "1.0.160" +name = "windows-future" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" dependencies = [ - "serde_derive", + "windows-core", + "windows-link", ] [[package]] -name = "serde_derive" -version = "1.0.160" +name = "windows-implement" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.100", ] [[package]] -name = "sha2" -version = "0.10.6" +name = "windows-interface" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] -name = "sha3" -version = "0.10.7" +name = "windows-link" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" -dependencies = [ - "digest", - "keccak", -] +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" [[package]] -name = "signature" -version = "1.6.4" +name = "windows-numerics" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" dependencies = [ - "digest", - "rand_core 0.6.4", + "windows-core", + "windows-link", ] [[package]] -name = "subtle" -version = "2.4.1" +name = "windows-result" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] [[package]] -name = "syn" -version = "1.0.109" +name = "windows-strings" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "windows-link", ] [[package]] -name = "syn" -version = "2.0.14" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "windows-targets", ] [[package]] -name = "thiserror" -version = "1.0.40" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "thiserror-impl", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] -name = "thiserror-impl" -version = "1.0.40" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.14", -] +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "typenum" -version = "1.16.0" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "unicode-ident" -version = "1.0.8" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "version_check" -version = "0.9.4" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows_x86_64_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "bitflags 2.9.0", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "xxhash-rust" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "zerocopy" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/payment-channel-ckb/devnet/contracts/Cargo.toml b/payment-channel-ckb/devnet/contracts/Cargo.toml index bd68a6e..901ae51 100644 --- a/payment-channel-ckb/devnet/contracts/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/Cargo.toml @@ -1,15 +1,22 @@ [workspace] -members = [ "contracts/perun-channel-lockscript" - , "contracts/perun-channel-typescript" - , "contracts/perun-funds-lockscript" - , "contracts/perun-common" - , "contracts/sample-udt" - ] -exclude = ["tests"] + +resolver = "2" + +members = [ + # Please don't remove the following line, we use it to automatically + # detect insertion point for newly generated crates. + # @@INSERTION_POINT@@ + "contracts/perun-vchannel-lockscript", + "contracts/perun-vchannel-typescript", + "contracts/sample-udt", + "contracts/perun-funds-lockscript", + "contracts/perun-channel-typescript", + "contracts/perun-channel-lockscript", + "tests", +] [profile.release] overflow-checks = true -opt-level = 's' -lto = false +strip = false codegen-units = 1 -panic = 'abort' +debug = true diff --git a/payment-channel-ckb/devnet/contracts/Makefile b/payment-channel-ckb/devnet/contracts/Makefile new file mode 100644 index 0000000..5c67060 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/Makefile @@ -0,0 +1,152 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +# When this is set, a single contract will be built instead of all contracts +CONTRACT := +# By default, we would clean build/{release,debug} folder first, in case old +# contracts are mixed together with new ones, if for some reason you want to +# revert this behavior, you can change this to anything other than true +CLEAN_BUILD_DIR_FIRST := true +BUILD_DIR := build/$(MODE) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +# Pass setups to child make processes +export CUSTOM_RUSTFLAGS +export TOP +export CARGO_ARGS +export MODE +export CLANG +export BUILD_DIR + +default: build test + +build: + @if [ "x$(CLEAN_BUILD_DIR_FIRST)" = "xtrue" ]; then \ + echo "Cleaning $(BUILD_DIR) directory..."; \ + rm -rf $(BUILD_DIR); \ + fi + mkdir -p $(BUILD_DIR) + @set -eu; \ + if [ "x$(CONTRACT)" = "x" ]; then \ + for contract in $(wildcard contracts/*); do \ + $(MAKE) -e -C $$contract build; \ + done; \ + for sim in $(wildcard native-simulators/*); do \ + cargo build -p $$(basename $$sim) $(CARGO_ARGS); \ + done; \ + else \ + $(MAKE) -e -C contracts/$(CONTRACT) build; \ + cargo build -p $(CONTRACT)-sim; \ + fi; + +# Run a single make task for a specific contract. For example: +# +# make run CONTRACT=stack-reorder TASK=adjust_stack_size STACK_SIZE=0x200000 +TASK := +run: + $(MAKE) -e -C contracts/$(CONTRACT) $(TASK) + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test --lib \ + --no-fail-fast \ + --manifest-path ./tests/Cargo.toml \ + -- --show-output --nocapture +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + rm -rf build + cargo clean + +TEMPLATE_TYPE := --git +TEMPLATE_REPO := https://github.com/cryptape/ckb-script-templates +CRATE := +TEMPLATE := contract +DESTINATION := contracts +generate: + @set -eu; \ + if [ "x$(CRATE)" = "x" ]; then \ + mkdir -p $(DESTINATION); \ + cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \ + --destination $(DESTINATION); \ + GENERATED_DIR=$$(ls -dt $(DESTINATION)/* | head -n 1); \ + if [ -f "$$GENERATED_DIR/.cargo-generate/tests.rs" ]; then \ + cat $$GENERATED_DIR/.cargo-generate/tests.rs >> tests/src/tests.rs; \ + rm -rf $$GENERATED_DIR/.cargo-generate/; \ + fi; \ + sed "s,@@INSERTION_POINT@@,@@INSERTION_POINT@@\n \"$$GENERATED_DIR\"\,," Cargo.toml > Cargo.toml.new; \ + mv Cargo.toml.new Cargo.toml; \ + else \ + mkdir -p $(DESTINATION); \ + cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) $(TEMPLATE) \ + --destination $(DESTINATION) \ + --name $(CRATE); \ + if [ -f "$(DESTINATION)/$(CRATE)/.cargo-generate/tests.rs" ]; then \ + cat $(DESTINATION)/$(CRATE)/.cargo-generate/tests.rs >> tests/src/tests.rs; \ + rm -rf $(DESTINATION)/$(CRATE)/.cargo-generate/; \ + fi; \ + sed '/@@INSERTION_POINT@@/s/$$/\n "$(DESTINATION)\/$(CRATE)",/' Cargo.toml > Cargo.toml.new; \ + mv Cargo.toml.new Cargo.toml; \ + fi; + +generate-native-simulator: + @set -eu; \ + if [ -z "$(CRATE)" ]; then \ + echo "Error: Must have CRATE="; \ + exit 1; \ + fi; \ + mkdir -p native-simulators; \ + cargo generate $(TEMPLATE_TYPE) $(TEMPLATE_REPO) native-simulator \ + -n $(CRATE)-sim \ + --destination native-simulators; \ + sed '/@@INSERTION_POINT@@/s/$$/\n "native-simulators\/$(CRATE)-sim",/' Cargo.toml > Cargo.toml.new; \ + mv Cargo.toml.new Cargo.toml; \ + if [ ! -f "contracts/$(CRATE)/Cargo.toml" ]; then \ + echo "Warning: This is a non-existent contract and needs to be processed manually"; \ + echo " Otherwise compilation may fail."; \ + fi; + +prepare: + rustup target add riscv64imac-unknown-none-elf + +# Generate checksum info for reproducible build +CHECKSUM_FILE := build/checksums-$(MODE).txt +checksum: build + shasum -a 256 build/$(MODE)/* > $(CHECKSUM_FILE) + +.PHONY: build test check clippy fmt cargo clean prepare checksum diff --git a/payment-channel-ckb/devnet/contracts/README.md b/payment-channel-ckb/devnet/contracts/README.md index 0f60dfb..76394d5 100644 --- a/payment-channel-ckb/devnet/contracts/README.md +++ b/payment-channel-ckb/devnet/contracts/README.md @@ -27,19 +27,60 @@ Basically a NFT script with extra functionality. This script handle access rights to all funds belonging to a Perun channel. It ensures that only channel participants are able to consume said funds. +## Prerequisites +Update the rustc version to 1.85.0 and install the following: +``` +sudo apt install gcc-riscv64-unknown-elf binutils-riscv64-unknown-elf \ +libc6-dev-riscv64-cross libc6-riscv64-cross linux-libc-dev-riscv64-cross +``` +``` +wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 18 && rm llvm.sh +``` +``` +cargo install cargo-generate +``` +Add the target: +``` +rustup target add riscv64imac-unknown-none-elf +``` + +## Build and Test Build contracts: ``` sh -capsule build +chmod +x ./setup_env.sh +``` + +``` sh +make prepare +``` + +``` sh +source ./setup_env.sh build && make build ``` Run tests: ``` sh -capsule test +source ./setup_env.sh test && make test ``` +or run them using the IDE ## perun-common -Additionally to the available contracts we extracted common functionality into +Additionally, to the available contracts we extracted common functionality into its own `perun-common` crate which gives some additional helpers and convenience functions when interacting with types used in Perun contracts. + +## Problems +### 1. Missing file gnu/stubs-lp64.h +A common issue when compiling for RISC-V is the missing file: `gnu/stubs-lp64.h` + +If the necessary packages are already installed, the file `/usr/riscv64-linux-gnu/include/gnu/stubs-lp64d.h` +should exist instead. This is due to the toolchain using the lp64d ABI (which includes double-precision floating point support) rather than plain lp64. + +To resolve this, simply create a symbolic link: +``` +sudo ln -s /usr/riscv64-linux-gnu/include/gnu/stubs-lp64d.h /usr/riscv64-linux-gnu/include/gnu/stubs-lp64.h +``` + +Then try compiling again. diff --git a/payment-channel-ckb/devnet/contracts/capsule.toml b/payment-channel-ckb/devnet/contracts/capsule.toml deleted file mode 100644 index a6549a9..0000000 --- a/payment-channel-ckb/devnet/contracts/capsule.toml +++ /dev/null @@ -1,27 +0,0 @@ -# [rust] -# # path of rust contracts workspace directory, -# # a `Cargo.toml` file is expected under the directory. -# workspace_dir = "." -# toolchain = "nightly-2022-08-01" -# docker_image = "thewawar/ckb-capsule:2022-08-01" - -# capsule version -version = "0.9.2" -# path of deployment config file -deployment = "deployment/dev/deployment.toml" - -[[contracts]] -name = "perun-channel-lockscript" -template_type = "Rust" - -[[contracts]] -name = "perun-channel-typescript" -template_type = "Rust" - -[[contracts]] -name = "perun-funds-lockscript" -template_type = "Rust" - -[[contracts]] -name = "sample-udt" -template_type = "Rust" diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Cargo.toml index 049cf5b..fad5ec8 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Cargo.toml @@ -3,8 +3,12 @@ name = "perun-channel-lockscript" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -ckb-std = "0.10.0" -perun-common = { path = "../perun-common", default-features = false, features = ["contract"] } +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Makefile b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/README.md b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/README.md new file mode 100644 index 0000000..748e134 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/README.md @@ -0,0 +1,7 @@ +# perun-channel-lockscript + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/entry.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/lib.rs similarity index 62% rename from payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/entry.rs rename to payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/lib.rs index d8ea048..ecea67a 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/entry.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/lib.rs @@ -1,11 +1,19 @@ -// Import from `core` instead of from `std` since we are in no-std mode -use core::result::Result; +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] + +use ckb_std::default_alloc; +use core::arch::asm; + +ckb_std::entry!(program_entry); +default_alloc!(); // Import CKB syscalls and structures // https://docs.rs/ckb-std/ use ckb_std::{ ckb_constants::Source, ckb_types::{bytes::Bytes, prelude::*}, + debug, high_level::{load_cell_lock_hash, load_cell_type, load_script}, syscalls::SysError, }; @@ -22,6 +30,13 @@ use perun_common::{error::Error, perun_types::ChannelConstants}; // Note: This means, that each participant needs to use a secp256k1_blake160_sighash_all as input to interact with the channel. // This should not be a substantial restriction, since a payment input will likely be used anyway (e.g. for funding or fees). +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } +} + pub fn main() -> Result<(), Error> { let script = load_script()?; let args: Bytes = script.args().unpack(); @@ -31,19 +46,31 @@ pub fn main() -> Result<(), Error> { } // locate the ChannelConstants in the type script of the input cell. - let type_script = load_cell_type(0, Source::GroupInput)?.expect("type script not found"); - let type_script_args: Bytes = type_script.args().unpack(); + // the best practice is to loop all the input cells in the group + for i in 0.. { + // Loop over all input cells. + let type_script = match load_cell_type(i, Source::GroupInput) { + Ok(Some(script)) => script, + Ok(None) => { + debug!("Error: Type script not found"); + return Err(Error::PCTSNotFound); + } + Err(SysError::IndexOutOfBound) => break, + Err(err) => return Err(err.into()), + }; + let type_script_args: Bytes = type_script.args().unpack(); - let constants = ChannelConstants::from_slice(&type_script_args) - .expect("unable to parse args as channel parameters"); + let constants = ChannelConstants::from_slice(&type_script_args) + .expect("unable to parse args as channel parameters"); - let is_participant = verify_is_participant( - &constants.params().party_a().unlock_script_hash().unpack(), - &constants.params().party_b().unlock_script_hash().unpack(), - )?; + let is_participant = verify_is_participant( + &constants.params().party_a().unlock_script_hash().unpack(), + &constants.params().party_b().unlock_script_hash().unpack(), + )?; - if !is_participant { - return Err(Error::NotParticipant); + if !is_participant { + return Err(Error::NotParticipant); + } } return Ok(()); @@ -59,8 +86,8 @@ pub fn verify_is_participant( // Loop over all input cells. let cell_lock_script_hash = match load_cell_lock_hash(i, Source::Input) { Ok(lock_hash) => lock_hash, - Err(SysError::IndexOutOfBound) => return Ok(false), - Err(err) => return Err(err.into()), + Result::Err(SysError::IndexOutOfBound) => return Ok(false), + Result::Err(err) => return Result::Err(err.into()), }; if cell_lock_script_hash[..] == unlock_script_hash_a[..] || cell_lock_script_hash[..] == unlock_script_hash_b[..] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/main.rs index 9306fc4..42463dc 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/main.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/main.rs @@ -1,32 +1,4 @@ -//! Generated by capsule -//! -//! `main.rs` is used to define rust lang items and modules. -//! See `entry.rs` for the `main` function. -//! See `error.rs` for the `Error` type. +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] -#![no_std] -#![no_main] -#![feature(asm_sym)] -#![feature(lang_items)] -#![feature(alloc_error_handler)] -#![feature(panic_info_message)] - -// define modules -mod entry; - -use ckb_std::default_alloc; -use core::arch::asm; - -ckb_std::entry!(program_entry); -default_alloc!(); - -/// program entry -/// -/// Both `argc` and `argv` can be omitted. -fn program_entry(_argc: u64, _argv: *const *const u8) -> i8 { - // Call main function and return error code - match entry::main() { - Ok(_) => 0, - Err(err) => err as i8, - } -} +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Cargo.toml index 85ccd63..6256810 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Cargo.toml @@ -3,8 +3,12 @@ name = "perun-channel-typescript" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -ckb-std = "0.10.0" -perun-common = { path = "../perun-common", default-features = false, features = ["contract"] } +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Makefile b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/README.md b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/README.md new file mode 100644 index 0000000..0e2840b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/README.md @@ -0,0 +1,7 @@ +# perun-channel-typescript + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/entry.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/lib.rs similarity index 53% rename from payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/entry.rs rename to payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/lib.rs index e581e4d..0cdffe7 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/entry.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/lib.rs @@ -1,9 +1,17 @@ +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] + +use ckb_std::default_alloc; + +ckb_std::entry!(program_entry); +default_alloc!(); // Import from `core` instead of from `std` since we are in no-std mode use core::result::Result; // Import heap related library from `alloc` // https://doc.rust-lang.org/alloc/index.html -use alloc::{self, vec}; - +use alloc::vec; +use core::iter::IntoIterator; // Import CKB syscalls and structures // https://docs.rs/ckb-std/ use ckb_std::{ @@ -15,53 +23,39 @@ use ckb_std::{ }, debug, high_level::{ - load_cell_capacity, load_cell_data, load_cell_lock, load_cell_lock_hash, load_header, - load_script, load_script_hash, load_transaction, load_witness_args, + load_cell_capacity, load_cell_data, load_cell_lock, load_cell_lock_hash, load_cell_type, + load_cell_type_hash, load_script, load_script_hash, load_transaction, load_witness_args, }, - syscalls::{self, SysError}, }; use perun_common::{ + channels::{ + find_cell_by_type_hash, get_channel_action, unpack_byte32, unpack_u64, + verify_channel_id_integrity, verify_max_one_channel, verify_thread_token_integrity, + verify_time_lock_expired, PChannelAction, + }, error::Error, - helpers::blake2b256, perun_types::{ - Balances, ChannelConstants, ChannelParameters, ChannelState, ChannelStatus, ChannelToken, - ChannelWitness, ChannelWitnessUnion, SEC1EncodedPubKey, + Balances, ChannelConstants, ChannelParameters, ChannelState, ChannelStatus, ChannelWitness, + ChannelWitnessUnion, Dispute, IndexMap, ParentsVec, SEC1EncodedPubKey, VCChannelConstants, + VirtualChannelStatus, + }, + sig::{ + verify_signature, + ethereum_message_hash, }, - sig::verify_signature, }; const SUDT_MIN_LEN: usize = 16; -/// ChannelAction describes what kind of interaction with the channel is currently happening. -/// -/// If there is an old ChannelStatus, it is the status of the channel before the interaction. -/// The old ChannelStatus lives in the cell data of the pcts input cell. -/// It is stored in the parallel outputs_data array of the transaction that produced the consumed -/// channel output cell. -/// -/// If there is a new ChannelStatus, it is the status of the channel after the interaction. -/// The new ChannelStatus lives in the cell data of the pcts output cell. It is stored in the -/// parallel outputs_data array of the consuming transaction -pub enum ChannelAction { - /// Progress indicates that a channel is being progressed. This means that a channel cell is consumed - /// in the inputs and the same channel with updated state is progressed in the outputs. - /// The possible redeemers associated with the Progress action are Fund and Dispute. - Progress { - old_status: ChannelStatus, - new_status: ChannelStatus, - }, // one PCTS input, one PCTS output - /// Start indicates that a channel is being started. This means that a **new channel** lives in the - /// output cells of this transaction. No channel cell is consumes as an input. - /// As Start does not consume a channel cell, there is no Witness associated with the Start action. - Start { new_status: ChannelStatus }, // no PCTS input, one PCTS output - /// Close indicates that a channel is being closed. This means that a channel's cell is consumed without being - /// recreated in the outputs with updated state. The possible redeemers associated with the Close action are - /// Close, Abort and ForceClose. - /// The channel type script assures that all funds are payed out to the correct parties upon closing. - Close { old_status: ChannelStatus }, // one PCTS input , no PCTS output +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } } pub fn main() -> Result<(), Error> { + debug!("PCTS"); let script = load_script()?; let args: Bytes = script.args().unpack(); @@ -91,8 +85,8 @@ pub fn main() -> Result<(), Error> { debug!("get_channel_action passed"); match channel_action { - ChannelAction::Start { new_status } => check_valid_start(&new_status, &channel_constants), - ChannelAction::Progress { + PChannelAction::Start { new_status } => check_valid_start(&new_status, &channel_constants), + PChannelAction::Progress { old_status, new_status, } => { @@ -105,7 +99,7 @@ pub fn main() -> Result<(), Error> { &channel_constants, ) } - ChannelAction::Close { old_status } => { + PChannelAction::Close { old_status } => { let channel_witness = load_witness()?; debug!("load_witness passed"); check_valid_close(&old_status, &channel_witness, &channel_constants) @@ -242,42 +236,18 @@ pub fn check_valid_progress( } ChannelWitnessUnion::Dispute(d) => { debug!("ChannelWitnessUnion::Dispute"); + check_normal_dispute(old_status, new_status, channel_constants, &d) + } - // An honest party will dispute a channel, e.g. if its peer does not respond and it wants to close - // the channel. For this, the honest party needs to provide the latest state (in the "new" channel status) - // as well as a valid signature by each party on that state (in the witness). After the expiration of the - // relative time lock (challenge duration), the honest party can forcibly close the channel. - // If a malicious party disputes with an old channel state, an honest party can dispute again with - // the latest state (with higher version number) and the corresponding signatures within the challenge - // duration. - - // First, we verify the integrity of the channel state. For this, the following must hold: - // - channel id is equal - // - version number is increasing (see verify_increasing_version_number) - // - sum of balances is equal - // - old state is not final - verify_channel_state_progression(old_status, &new_status.state())?; - debug!("verify_channel_state_progression passed"); - - // One cannot dispute if funding is not complete. - verify_status_funded(old_status)?; - debug!("verify_status_funded passed"); - - // The disputed flag in the new status must be set. This indicates that the channel can be closed - // forcibly after the expiration of the challenge duration in a later transaction. - verify_status_disputed(new_status)?; - debug!("verify_status_disputed passed"); - - // We verify that the signatures of both parties are valid on the new channel state. - verify_valid_state_sigs( - &d.sig_a().unpack(), - &d.sig_b().unpack(), - &new_status.state(), - &channel_constants.params().party_a().pub_key(), - &channel_constants.params().party_b().pub_key(), + ChannelWitnessUnion::VCDispute(vcd) => { + debug!("ChannelWitnessUnion::VCDispute"); + check_normal_dispute( + old_status, + new_status, + channel_constants, + &vcd.parent_state_sigs(), )?; - debug!("verify_valid_state_sigs passed"); - Ok(()) + check_vc_dispute(old_status, new_status) } // Close, ForceClose and Abort may not happen as channel progression (if there is a continuing channel output). ChannelWitnessUnion::Close(_) => Err(Error::ChannelCloseWithChannelOutput), @@ -286,6 +256,92 @@ pub fn check_valid_progress( } } +pub fn check_vc_dispute( + old_status: &ChannelStatus, + new_status: &ChannelStatus, +) -> Result<(), Error> { + debug!("check_vc_dispute"); + + //A vc cell can only be created once by this channel cell + if !(!old_status.disputed().to_bool() && new_status.disputed().to_bool()) { + return Err(Error::InvalidVCTxStart); + } + debug!("Verified that vc cell can only be created once by this lc cell"); + + //A vc cell having the same vcts hash should exist in the outputs + let vcts_hash = new_status.vcts_hash().unpack(); + let output_vc_idx = match find_cell_by_type_hash(&vcts_hash, Source::Output) { + Ok(Some(idx)) => idx, + Ok(None) => return Err(Error::VCOutputCellMissingIngStartTx), + Err(err) => return Err(err.into()), + }; + debug!("Verified that vc cell having the same vcts hash exists in the outputs"); + let vc_status = match load_cell_data(output_vc_idx, Source::Output) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + verify_vc_parent(&vc_status)?; + debug!("verify_vc_parent passed"); + + //Funds in lc are blocked for vc + verify_locked_funds(new_status, &vc_status)?; + debug!("verify_locked_funds passed"); + debug!("check_vc_dispute passed"); + Ok(()) +} + +pub fn check_normal_dispute( + old_status: &ChannelStatus, + new_status: &ChannelStatus, + channel_constants: &ChannelConstants, + d: &Dispute, +) -> Result<(), Error> { + // An honest party will dispute a channel, e.g. if its peer does not respond and it wants to close + // the channel. For this, the honest party needs to provide the latest state (in the "new" channel status) + // as well as a valid signature by each party on that state (in the witness). After the expiration of the + // relative time lock (challenge duration), the honest party can forcibly close the channel. + // If a malicious party disputes with an old channel state, an honest party can dispute again with + // the latest state (with higher version number) and the corresponding signatures within the challenge + // duration. + + // In normal cases (no vc dispute), we verify the integrity of the channel state. For this, the following must hold: + // - channel id is equal + // - version number is increasing (see verify_increasing_version_number) + // - sum of balances is equal + // - old state is not final + // In case of vc disputes, we allow version number to be non-decreasing + debug!("check_normal_dispute"); + if !old_status.vc_disputed().to_bool() { + debug!("verify_channel_state_progression"); + verify_channel_state_progression(old_status, &new_status.state())?; + } else { + debug!("verify_vc_parent_state_progression"); + verify_vc_parent_state_progression(old_status, &new_status.state())?; + } + debug!("verify_channel_state_progression passed"); + + // One cannot dispute if funding is not complete. + verify_status_funded(old_status)?; + debug!("verify_status_funded passed"); + + // The disputed flag in the new status must be set. This indicates that the channel can be closed + // forcibly after the expiration of the challenge duration in a later transaction. + verify_status_disputed(new_status)?; + debug!("verify_status_disputed passed"); + + // We verify that the signatures of both parties are valid on the new channel state. + verify_valid_state_sigs( + &d.sig_a().unpack(), + &d.sig_b().unpack(), + &new_status.state(), + &channel_constants.params().party_a().pub_key(), + &channel_constants.params().party_b().pub_key(), + )?; + debug!("verify_valid_state_sigs passed"); + debug!("check_normal_dispute passed"); + Ok(()) +} + pub fn check_valid_close( old_status: &ChannelStatus, channel_witness: &ChannelWitness, @@ -296,7 +352,7 @@ pub fn check_valid_close( // At this point we know that this transaction closes the channel. There are three different kinds of // closing: Abort, ForceClose and Close. Which kind of closing is performed depends on the witness. // Every channel closing transaction must pay out all funds the the channel participants. The amount - // to be payed to each party + // to be paid to each party let channel_capacity = load_cell_capacity(0, Source::GroupInput)?; match channel_witness.to_enum() { ChannelWitnessUnion::Abort(_) => { @@ -310,37 +366,55 @@ pub fn check_valid_close( verify_status_not_funded(old_status)?; debug!("verify_status_not_funded passed"); - // We verify that every party is payed the amount of funds that it has locked to the channel so far. + // We verify that every party is paid the amount of funds that it has locked to the channel so far. // If abourt is called, Party A must have fully funded the channel and Party B can not have funded // the channel because of our funding protocol. - verify_all_payed( + verify_all_paid( &old_status.state().balances().clear_index(PARTY_B_INDEX)?, channel_capacity, channel_constants, true, )?; - debug!("verify_all_payed passed"); + debug!("verify_all_paid passed"); Ok(()) } ChannelWitnessUnion::ForceClose(_) => { debug!("ChannelWitnessUnion::ForceClose"); - // A force close can be performed after the channel was disputed and the challenge duration has - // expired. Upon force close, each party is payed according to the balance distribution in the - // latest state. - verify_status_funded(old_status)?; - debug!("verify_status_funded passed"); - verify_time_lock_expired(channel_constants.params().challenge_duration().unpack())?; - debug!("verify_time_lock_expired passed"); - verify_status_disputed(old_status)?; - debug!("verify_status_disputed passed"); - verify_all_payed( - &old_status.state().balances(), - channel_capacity, - channel_constants, - false, - )?; - debug!("verify_all_payed passed"); - Ok(()) + if old_status.vc_disputed().to_bool() { + debug!("Force Close (VC)"); + let vc_pcts_hash = old_status.vcts_hash().unpack(); + let input_vc_idx = match find_cell_by_type_hash(&vc_pcts_hash, Source::Input) { + Ok(Some(idx)) => idx, + Ok(None) => return Err(Error::VCInputCellMissingInClose1Tx), + Err(err) => return Err(err.into()), + }; + let vc_status = match load_cell_data(input_vc_idx, Source::Input) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + let vcts = match load_cell_type(input_vc_idx, Source::Input) { + Ok(Some(script)) => script, + Ok(None) => return Err(Error::VCInputCellMissingInClose1Tx), + Err(err) => return Err(err.into()), + }; + let vcts_args: Bytes = vcts.args().unpack(); + let vchannel_constants = match VCChannelConstants::from_slice(&vcts_args) { + Ok(args) => args, + Err(err) => { + debug!("Error encountered while reading VCChannelConstants"); + return Err(err.into()); + } + }; + check_vc_force_close( + old_status, + channel_constants, + &vc_status, + &vchannel_constants, + ) + } else { + debug!("Force Close (Normal)"); + check_normal_force_close(old_status, channel_constants, channel_capacity) + } } ChannelWitnessUnion::Close(c) => { debug!("check_valid_close: Close"); @@ -361,19 +435,300 @@ pub fn check_valid_close( &channel_constants.params().party_a().pub_key(), &channel_constants.params().party_b().pub_key(), )?; - // We verify that each party is payed according to the balance distribution in the final state. - verify_all_payed( + // We verify that each party is paid according to the balance distribution in the final state. + verify_all_paid( &c.state().balances(), channel_capacity, channel_constants, false, )?; - debug!("verify_all_payed passed"); + debug!("verify_all_paid passed"); Ok(()) } ChannelWitnessUnion::Fund(_) => Err(Error::ChannelFundWithoutChannelOutput), ChannelWitnessUnion::Dispute(_) => Err(Error::ChannelDisputeWithoutChannelOutput), + ChannelWitnessUnion::VCDispute(_) => Err(Error::VCDisputeWithoutChannelOutput), + } +} + +pub fn check_vc_force_close( + old_status: &ChannelStatus, + channel_constants: &ChannelConstants, + vc_status: &VirtualChannelStatus, + vcts_args: &VCChannelConstants, +) -> Result<(), Error> { + debug!("check_vc_force_close"); + let channel_capacity = load_cell_capacity(0, Source::GroupInput)?; + + //perform closing checks for ledger channel + verify_status_funded(old_status)?; + debug!("verify_status_funded(lc) passed"); + verify_time_lock_expired(channel_constants.params().challenge_duration().unpack())?; + debug!("verify_time_lock_expired(lc) passed"); + verify_status_disputed(old_status)?; + debug!("verify_status_disputed(lc) passed"); + + //perform checks for child vc + verify_time_lock_expired(vcts_args.params().challenge_duration().unpack())?; + debug!("verify_time_lock_expired(vc) passed"); + + //check that the funds are payed out correctly + verify_all_paid_vc( + &old_status.state().balances(), + channel_capacity, + channel_constants, + &vc_status, + )?; + debug!("verify_all_paid_vc passed"); + Ok(()) +} + +pub fn check_normal_force_close( + old_status: &ChannelStatus, + channel_constants: &ChannelConstants, + channel_capacity: u64, +) -> Result<(), Error> { + debug!("ChannelWitnessUnion::ForceClose (Normal)"); + // A force close can be performed after the channel was disputed and the challenge duration has + // expired. Upon force close, each party is paid according to the balance distribution in the + // latest state. + + verify_status_funded(old_status)?; + debug!("verify_status_funded passed"); + verify_time_lock_expired(channel_constants.params().challenge_duration().unpack())?; + debug!("verify_time_lock_expired passed"); + verify_status_disputed(old_status)?; + debug!("verify_status_disputed passed"); + + // Check if this is a case where vc cell is being closed + verify_all_paid( + &old_status.state().balances(), + channel_capacity, + channel_constants, + false, + )?; + debug!("verify_all_paid passed"); + Ok(()) +} + +pub fn verify_locked_funds( + new_lc_status: &ChannelStatus, + new_vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + let vc_balances = new_vc_status.vcstate().balances(); + let locked_funds_in_lc = new_lc_status.state().balances().locked(); + let vc_id = new_vc_status.vcstate().channel_id(); + + for sub_alloc in locked_funds_in_lc.into_iter() { + if sub_alloc.id().as_slice() == vc_id.as_slice() { + if sub_alloc.balances().equal_in_sum(&vc_balances)? { + return Ok(()); + } else { + return Err(Error::UnequalBalanceInLockedFundsAndVirtualChannelBalance); + } + } + } + Err(Error::FundsForVCNotLocked) +} +pub fn verify_vc_parent(vc_status: &VirtualChannelStatus) -> Result<(), Error> { + let parents = vc_status.parents(); + let pcts_hash = load_script_hash()?; + let mut found = false; + for i in 0..parents.len() { + let parent = match parents.get(i) { + Some(parent) => parent, + None => return Err(Error::InvalidVCParentData), + }; + let parent_hash: [u8; 32] = parent.pcts_hash().unpack(); + if parent_hash == pcts_hash { + found = true; + break; + } + } + if !found { + return Err(Error::InvalidVCParentData); + } + Ok(()) +} + +pub fn verify_all_paid_vc( + lc_final_balances: &Balances, + lc_channel_capacity: u64, + lc_channel_constants: &ChannelConstants, + vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + debug!("verify_all_paid_vc"); + let vc_sudts = vc_status.vcstate().balances().sudts(); + let minimum_payment_a = lc_channel_constants + .params() + .party_a() + .payment_min_capacity() + .unpack(); + + let minimum_payment_b = lc_channel_constants + .params() + .party_b() + .payment_min_capacity() + .unpack(); + + let reimburse_a = lc_final_balances.sudts().get_locked_ckbytes(); + + let reimburse_b = reimburse_a; + let idx_map = match get_idx_map(&vc_status.parents()) { + Ok(map) => map, + Err(err) => return Err(err.into()), + }; + + let party_a_vc_participant_idx = get_vc_participant_idx(0, &idx_map)?; + let party_b_vc_participant_idx = get_vc_participant_idx(1, &idx_map)?; + + let ckbytes_balance_a = lc_final_balances.ckbytes().get(0)? + lc_channel_capacity + reimburse_a; + let ckbytes_balance_vc_a = vc_status + .vcstate() + .balances() + .ckbytes() + .get(party_a_vc_participant_idx)?; + let total_ckbytes_balance_a = ckbytes_balance_vc_a + ckbytes_balance_a; + let payment_script_hash_a: [u8; 32] = lc_channel_constants + .params() + .party_a() + .payment_script_hash() + .unpack(); + + let ckbytes_balance_b = lc_final_balances.ckbytes().get(1)? + reimburse_b; + let ckbytes_balance_vc_b = vc_status + .vcstate() + .balances() + .ckbytes() + .get(party_b_vc_participant_idx)?; + let total_ckbytes_balance_b = ckbytes_balance_vc_b + ckbytes_balance_b; + + let payment_script_hash_b: [u8; 32] = lc_channel_constants + .params() + .party_b() + .payment_script_hash() + .unpack(); + + let mut ckbytes_outputs_a = 0; + let mut ckbytes_outputs_b = 0; + + let mut udt_outputs_a = + vec![0u128; lc_final_balances.sudts().len().try_into().unwrap()].into_boxed_slice(); + let mut udt_outputs_b = + vec![0u128; lc_final_balances.sudts().len().try_into().unwrap()].into_boxed_slice(); + + let outputs = load_transaction()?.raw().outputs(); + + // Note: Currently it is allowed to pay out a party's CKBytes in the capacity field of an + // output, that is used as SUDT payment. + for (i, output) in outputs.into_iter().enumerate() { + let output_lock_script_hash = load_cell_lock_hash(i, Source::Output)?; + + if output_lock_script_hash[..] == payment_script_hash_a[..] { + if output.type_().is_some() { + let (sudt_idx, amount) = get_sudt_amount( + lc_final_balances, + i, + &output.type_().to_opt().expect("checked above"), + )?; + udt_outputs_a[sudt_idx] += amount; + } + let output_cap: u64 = output.capacity().unpack(); + ckbytes_outputs_a += output_cap; + } + if output_lock_script_hash[..] == payment_script_hash_b[..] { + if output.type_().is_some() { + let (sudt_idx, amount) = get_sudt_amount( + lc_final_balances, + i, + &output.type_().to_opt().expect("checked above"), + )?; + udt_outputs_b[sudt_idx] += amount; + } + let output_cap: u64 = output.capacity().unpack(); + ckbytes_outputs_b += output_cap; + } + } + + // Parties with balances below the minimum capacity of the payment script + // are not required to be payed. + if (total_ckbytes_balance_a > ckbytes_outputs_a && total_ckbytes_balance_a >= minimum_payment_a) + || (total_ckbytes_balance_b > ckbytes_outputs_b + && total_ckbytes_balance_b >= minimum_payment_b) + { + return Err(Error::NotAllPaid); + } + + if !lc_final_balances.sudts().fully_represented_vc( + 0, + party_a_vc_participant_idx, + &vc_sudts, + &udt_outputs_a, + )? { + return Err(Error::NotAllPaid); + } + if !lc_final_balances.sudts().fully_represented_vc( + 1, + party_b_vc_participant_idx, + &vc_sudts, + &udt_outputs_b, + )? { + return Err(Error::NotAllPaid); } + Ok(()) +} + +/// get the participant index in vc, for a given participant index in lc +pub fn get_vc_participant_idx(lc_participant_idx: u8, idx_map: &IndexMap) -> Result { + //CONTEXT: + //For any perun channel, the participant index of proposer is defined to be 0 and that of proposee is 1 + // Consider the situation where: + // Alice and Ingrid have a ledger channel (C_AI), + // Ingrid and Bob have lc C_IB, + // Alice and Bob have virtual channel VC_AB + // + // Let Bob be the proposer of the VC_AB then, + // participant index of Bob in VC_AB is 0 + // participant index of Alice in VC_AB is 1 + // In C_IB, let Ingrid be the proposer then, + // participant index of Ingrid in C_IB is 0 + // participant index of Bob in C_IB is 1 + // + // An index map exists for every parent of a VC. Thus VC_AB will have an index map for C_AI and one for C_IB + // The index map for C_IB will be [1,0]. Why? + // index_map[0] = 1 ==> This means the funds for Proposer of VC (aka Bob) is covered by the proposee of C_IB (aka Bob) ===> True according to given situation + // index_map[1] = 0 ==> This means the funds for Proposee of VC (aka Alice) is covered by the proposer of C_IB (aka Ingrid) ===> True according to given situation + // + // Which idx does this function return? + // Let this PCTS belong to C_IB, then + // calling this function for Bob i.e, get_vc_participant_idx(1, &index_map) should return 0 + // calling this function for Ingrid i.e, get_vc_participant_idx(0, &index_map) should return 1 + if idx_map.nth0().as_slice()[0] == lc_participant_idx { + return Ok(0); + } + if idx_map.nth1().as_slice()[0] == lc_participant_idx { + return Ok(1); + } + Err(Error::VCParticipantIdxNotFound) +} + +/// get the index map for the channel cell running this pcts +pub fn get_idx_map(parents: &ParentsVec) -> Result { + let pcts_hash = match load_cell_type_hash(0, Source::GroupInput)? { + Some(hash) => hash, + None => panic!("type script not found"), + }; + for i in 0..parents.len() { + let parent = match parents.get(i) { + Some(parent) => parent, + None => return Err(Error::InvalidVCParentData), + }; + let parent_hash: [u8; 32] = parent.pcts_hash().unpack(); + if parent_hash == pcts_hash { + return Ok(parent.idx_map()); + } + } + Err(Error::InvalidVCParentData) } pub fn load_witness() -> Result { @@ -393,28 +748,34 @@ pub fn verify_increasing_version_number( old_status: &ChannelStatus, new_state: &ChannelState, ) -> Result<(), Error> { - debug!( - "verify_increasing_version_number old_state disputed: {}", - old_status.disputed().to_bool() - ); - debug!( - "verify_increasing_version_number old: {}, new: {}", - old_status.state().version().unpack(), - new_state.version().unpack() - ); + let old_status_disputed: bool = old_status.disputed().to_bool(); + let old_state_version: u64 = old_status.state().version().unpack(); + let new_state_version: u64 = new_state.version().unpack(); + // Allow registering initial state - if !old_status.disputed().to_bool() - && old_status.state().version().unpack() == 0 - && new_state.version().unpack() == 0 - { + if !old_status_disputed && old_state_version == 0 && new_state_version == 0 { + debug!("Allow registering initial state"); return Ok(()); } - if old_status.state().version().unpack() < new_state.version().unpack() { + if old_state_version < new_state_version { return Ok(()); } Err(Error::VersionNumberNotIncreasing) } +pub fn verify_non_decreasing_version_number( + old_status: &ChannelStatus, + new_state: &ChannelState, +) -> Result<(), Error> { + let old_state_version: u64 = old_status.state().version().unpack(); + let new_state_version: u64 = new_state.version().unpack(); + + if old_state_version > new_state_version { + return Err(Error::InvalidVersionNumberVCProgressTx); + } + Ok(()) +} + pub fn verify_valid_state_sigs( sig_a: &Bytes, sig_b: &Bytes, @@ -422,7 +783,7 @@ pub fn verify_valid_state_sigs( pub_key_a: &SEC1EncodedPubKey, pub_key_b: &SEC1EncodedPubKey, ) -> Result<(), Error> { - let msg_hash = blake2b256(state.as_slice()); + let msg_hash = ethereum_message_hash(state.as_slice()); verify_signature(&msg_hash, sig_a, pub_key_a.as_slice())?; debug!("verify_valid_state_sigs: Signature A verified"); verify_signature(&msg_hash, sig_b, pub_key_b.as_slice())?; @@ -448,6 +809,8 @@ pub fn verify_equal_sum_of_balances( old_balances: &Balances, new_balances: &Balances, ) -> Result<(), Error> { + debug!("old balances {:?}", old_balances); + debug!("new balances {:?}", new_balances); if !old_balances.equal_in_sum(new_balances)? { return Err(Error::SumOfBalancesNotEqual); } @@ -466,10 +829,10 @@ pub fn verify_channel_continues_locked() -> Result<(), Error> { pub fn verify_no_funds_in_inputs(channel_constants: &ChannelConstants) -> Result<(), Error> { let num_inputs = load_transaction()?.raw().inputs().len(); for i in 0..num_inputs { - let cell_lock_hash = load_cell_lock(i, Source::Input)?; - if cell_lock_hash.code_hash().unpack()[..] - == channel_constants.pfls_code_hash().unpack()[..] - { + let cell_lockscript = load_cell_lock(i, Source::Input)?; + let lockscript_codehash: [u8; 32] = cell_lockscript.code_hash().unpack(); + let pfls_code_hash: [u8; 32] = channel_constants.pfls_code_hash().unpack(); + if lockscript_codehash[..] == pfls_code_hash[..] { return Err(Error::FundsInInputs); } } @@ -502,22 +865,24 @@ pub fn verify_funding_in_outputs( let expected_pcts_script_hash = load_script_hash()?; let outputs = load_transaction()?.raw().outputs(); - let expected_pfls_code_hash = channel_constants.pfls_code_hash().unpack(); + let expected_pfls_code_hash: [u8; 32] = channel_constants.pfls_code_hash().unpack(); let expected_pfls_hash_type = channel_constants.pfls_hash_type(); let mut capacity_sum: u64 = 0; for (i, output) in outputs.into_iter().enumerate() { - if output.lock().code_hash().unpack()[..] == expected_pfls_code_hash[..] + let output_lockscript_codehash: [u8; 32] = output.lock().code_hash().unpack(); + if output_lockscript_codehash[..] == expected_pfls_code_hash[..] && output.lock().hash_type().eq(&expected_pfls_hash_type) { let output_lock_args: Bytes = output.lock().args().unpack(); - let script_hash_in_pfls_args = Byte32::from_slice(&output_lock_args)?.unpack(); + let script_hash_in_pfls_args: [u8; 32] = + Byte32::from_slice(&output_lock_args)?.unpack(); if script_hash_in_pfls_args[..] == expected_pcts_script_hash[..] { - capacity_sum += output.capacity().unpack(); + capacity_sum += unpack_u64(&output.capacity()); } else { return Err(Error::InvalidPFLSInOutputs); } if output.type_().is_some() { - let (sudt_idx, amount) = get_sudt_amout( + let (sudt_idx, amount) = get_sudt_amount( initial_balance, i, &output.type_().to_opt().expect("checked above"), @@ -527,10 +892,6 @@ pub fn verify_funding_in_outputs( } } if capacity_sum != to_fund { - debug!( - "verify_funding_in_outputs: capacity_sum: {}, to_fund: {}", - capacity_sum, to_fund - ); return Err(Error::OwnFundingNotInOutputs); } if !initial_balance.sudts().fully_represented(idx, &udt_sum)? { @@ -577,10 +938,10 @@ pub fn verify_channel_params_compatibility(params: &ChannelParameters) -> Result return Err(Error::AppChannelsNotSupported); } if !params.is_ledger_channel().to_bool() { - return Err(Error::NonLedgerChannelsNotSupported); + return Err(Error::WrongChannelType); } if params.is_virtual_channel().to_bool() { - return Err(Error::VirtualChannelsNotSupported); + return Err(Error::WrongChannelType); } Ok(()) } @@ -589,7 +950,7 @@ pub fn verify_equal_channel_id( old_state: &ChannelState, new_state: &ChannelState, ) -> Result<(), Error> { - if old_state.channel_id().unpack()[..] != new_state.channel_id().unpack()[..] { + if unpack_byte32(&old_state.channel_id())[..] != unpack_byte32(&new_state.channel_id())[..] { return Err(Error::ChannelIdMismatch); } Ok(()) @@ -606,24 +967,14 @@ pub fn verify_channel_state_progression( Ok(()) } -pub fn verify_thread_token_integrity(thread_token: &ChannelToken) -> Result<(), Error> { - let inputs = load_transaction()?.raw().inputs(); - for input in inputs.into_iter() { - if input.previous_output().as_slice()[..] == thread_token.out_point().as_slice()[..] { - return Ok(()); - } - } - Err(Error::InvalidThreadToken) -} - -pub fn verify_channel_id_integrity( - channel_id: &Byte32, - params: &ChannelParameters, +pub fn verify_vc_parent_state_progression( + old_status: &ChannelStatus, + new_state: &ChannelState, ) -> Result<(), Error> { - let digest = blake2b256(params.as_slice()); - if digest[..] != channel_id.unpack()[..] { - return Err(Error::InvalidChannelId); - } + verify_equal_channel_id(&old_status.state(), new_state)?; + verify_non_decreasing_version_number(old_status, new_state)?; + verify_equal_sum_of_balances(&old_status.state().balances(), &new_state.balances())?; + verify_state_not_finalized(&old_status.state())?; Ok(()) } @@ -631,7 +982,7 @@ pub fn verify_state_valid_as_start( state: &ChannelState, pfls_min_capacity: u64, ) -> Result<(), Error> { - if state.version().unpack() != 0 { + if unpack_u64(&state.version()) != 0 { return Err(Error::StartWithNonZeroVersion); } if state.is_final().to_bool() { @@ -653,7 +1004,9 @@ pub fn verify_state_valid_as_start( pub fn verify_valid_lock_script(channel_constants: &ChannelConstants) -> Result<(), Error> { let lock_script = load_cell_lock(0, Source::GroupOutput)?; - if lock_script.code_hash().unpack()[..] != channel_constants.pcls_code_hash().unpack()[..] { + if unpack_byte32(&lock_script.code_hash())[..] + != unpack_byte32(&channel_constants.pcls_code_hash())[..] + { return Err(Error::InvalidPCLSCodeHash); } if !lock_script @@ -683,13 +1036,13 @@ pub fn verify_status_disputed(status: &ChannelStatus) -> Result<(), Error> { Ok(()) } -pub fn verify_all_payed( +pub fn verify_all_paid( final_balance: &Balances, channel_capacity: u64, channel_constants: &ChannelConstants, is_abort: bool, ) -> Result<(), Error> { - debug!("verify_all_payed"); + debug!("verify_all_paid"); debug!("is_abort: {}", is_abort); let minimum_payment_a = channel_constants .params() @@ -709,18 +1062,12 @@ pub fn verify_all_payed( } let ckbytes_balance_a = final_balance.ckbytes().get(0)? + channel_capacity + reimburse_a; - let payment_script_hash_a = channel_constants - .params() - .party_a() - .payment_script_hash() - .unpack(); + let payment_script_hash_a = + unpack_byte32(&channel_constants.params().party_a().payment_script_hash()); let ckbytes_balance_b = final_balance.ckbytes().get(1)? + reimburse_b; - let payment_script_hash_b = channel_constants - .params() - .party_b() - .payment_script_hash() - .unpack(); + let payment_script_hash_b = + unpack_byte32(&channel_constants.params().party_b().payment_script_hash()); debug!("ckbytes_balance_a: {}", ckbytes_balance_a); debug!("ckbytes_balance_b: {}", ckbytes_balance_b); @@ -742,46 +1089,72 @@ pub fn verify_all_payed( if output_lock_script_hash[..] == payment_script_hash_a[..] { if output.type_().is_some() { - let (sudt_idx, amount) = get_sudt_amout( + let (sudt_idx, amount) = get_sudt_amount( final_balance, i, &output.type_().to_opt().expect("checked above"), )?; udt_outputs_a[sudt_idx] += amount; } - ckbytes_outputs_a += output.capacity().unpack(); + ckbytes_outputs_a += unpack_u64(&output.capacity()); } if output_lock_script_hash[..] == payment_script_hash_b[..] { if output.type_().is_some() { - let (sudt_idx, amount) = get_sudt_amout( + let (sudt_idx, amount) = get_sudt_amount( final_balance, i, &output.type_().to_opt().expect("checked above"), )?; udt_outputs_b[sudt_idx] += amount; } - ckbytes_outputs_b += output.capacity().unpack(); + ckbytes_outputs_b += unpack_u64(&output.capacity()); } } debug!("ckbytes_outputs_a: {}", ckbytes_outputs_a); debug!("ckbytes_outputs_b: {}", ckbytes_outputs_b); // Parties with balances below the minimum capacity of the payment script - // are not required to be payed. + // are not required to be paid. if (ckbytes_balance_a > ckbytes_outputs_a && ckbytes_balance_a >= minimum_payment_a) || (ckbytes_balance_b > ckbytes_outputs_b && ckbytes_balance_b >= minimum_payment_b) { - return Err(Error::NotAllPayed); + return Err(Error::NotAllPaid); } debug!("udt_outputs_a: {:?}", udt_outputs_a); debug!("udt_outputs_b: {:?}", udt_outputs_b); if !final_balance.sudts().fully_represented(0, &udt_outputs_a)? { - return Err(Error::NotAllPayed); + return Err(Error::NotAllPaid); } if !final_balance.sudts().fully_represented(1, &udt_outputs_b)? { - return Err(Error::NotAllPayed); + return Err(Error::NotAllPaid); + } + Ok(()) +} + +pub fn verify_state_finalized(state: &ChannelState) -> Result<(), Error> { + if !state.is_final().to_bool() { + return Err(Error::StateNotFinal); + } + Ok(()) +} + +pub fn verify_different_payment_addresses( + channel_constants: &ChannelConstants, +) -> Result<(), Error> { + let payment_script_hash_a: [u8; 32] = channel_constants + .params() + .party_a() + .payment_script_hash() + .unpack(); + let payment_script_hash_b: [u8; 32] = channel_constants + .params() + .party_b() + .payment_script_hash() + .unpack(); + if payment_script_hash_a[..] == payment_script_hash_b[..] { + return Err(Error::SamePaymentAddress); } Ok(()) } @@ -791,7 +1164,7 @@ pub fn verify_all_payed( // (max_capacity of the SUDT asset - actual occupied capacity of the SUDT type script), if the SUDT asset's max_capacity // is smaller than the payment_min_capacity of the participant. We do not do this for now, because it is an extreme edge case // and the max_capacity of an SUDT should never be set that low. -pub fn get_sudt_amout( +pub fn get_sudt_amount( balances: &Balances, output_idx: usize, type_script: &Script, @@ -806,99 +1179,3 @@ pub fn get_sudt_amout( buf.copy_from_slice(&sudt_data[..SUDT_MIN_LEN]); return Ok((sudt_idx, u128::from_le_bytes(buf))); } - -pub fn verify_time_lock_expired(time_lock: u64) -> Result<(), Error> { - let old_header = load_header(0, Source::GroupInput)?; - let old_timestamp = old_header.raw().timestamp().unpack(); - let current_time = find_closest_current_time(); - if old_timestamp + time_lock > current_time { - return Err(Error::TimeLockNotExpired); - } - Ok(()) -} - -pub fn find_closest_current_time() -> u64 { - let mut latest_time = 0; - for i in 0.. { - match load_header(i, Source::HeaderDep) { - Ok(header) => { - let timestamp = header.raw().timestamp().unpack(); - if timestamp > latest_time { - latest_time = timestamp; - } - } - Err(_) => break, - } - } - latest_time -} - -pub fn verify_state_finalized(state: &ChannelState) -> Result<(), Error> { - if !state.is_final().to_bool() { - return Err(Error::StateNotFinal); - } - Ok(()) -} - -pub fn get_channel_action() -> Result { - let input_status_opt = load_cell_data(0, Source::GroupInput) - .ok() - .map(|data| ChannelStatus::from_slice(data.as_slice())) - .map_or(Ok(None), |v| v.map(Some))?; - - let output_status_opt = load_cell_data(0, Source::GroupOutput) - .ok() - .map(|data| ChannelStatus::from_slice(data.as_slice())) - .map_or(Ok(None), |v| v.map(Some))?; - - match (input_status_opt, output_status_opt) { - (Some(old_status), Some(new_status)) => Ok(ChannelAction::Progress { - old_status, - new_status, - }), - (Some(old_status), None) => Ok(ChannelAction::Close { old_status }), - (None, Some(new_status)) => Ok(ChannelAction::Start { new_status }), - (None, None) => Err(Error::UnableToLoadAnyChannelStatus), - } -} - -/// verify_max_one_channel verifies that there is at most one channel in the group input and group output respectively. -pub fn verify_max_one_channel() -> Result<(), Error> { - if count_cells(Source::GroupInput)? > 1 || count_cells(Source::GroupOutput)? > 1 { - return Err(Error::MoreThanOneChannel); - } else { - return Ok(()); - } -} - -pub fn count_cells(source: Source) -> Result { - let mut null_buf: [u8; 0] = []; - for i in 0.. { - match syscalls::load_cell(&mut null_buf, 0, i, source) { - Ok(_) => continue, - Err(SysError::LengthNotEnough(_)) => continue, - Err(SysError::IndexOutOfBound) => return Ok(i), - Err(err) => return Err(err.into()), - } - } - Ok(0) -} - -pub fn verify_different_payment_addresses( - channel_constants: &ChannelConstants, -) -> Result<(), Error> { - if channel_constants - .params() - .party_a() - .payment_script_hash() - .unpack()[..] - == channel_constants - .params() - .party_b() - .payment_script_hash() - .unpack()[..] - { - return Err(Error::SamePaymentAddress); - } - Ok(()) -} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/main.rs index 9306fc4..42463dc 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/main.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/main.rs @@ -1,32 +1,4 @@ -//! Generated by capsule -//! -//! `main.rs` is used to define rust lang items and modules. -//! See `entry.rs` for the `main` function. -//! See `error.rs` for the `Error` type. +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] -#![no_std] -#![no_main] -#![feature(asm_sym)] -#![feature(lang_items)] -#![feature(alloc_error_handler)] -#![feature(panic_info_message)] - -// define modules -mod entry; - -use ckb_std::default_alloc; -use core::arch::asm; - -ckb_std::entry!(program_entry); -default_alloc!(); - -/// program entry -/// -/// Both `argc` and `argv` can be omitted. -fn program_entry(_argc: u64, _argv: *const *const u8) -> i8 { - // Call main function and return error code - match entry::main() { - Ok(_) => 0, - Err(err) => err as i8, - } -} +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml deleted file mode 100644 index fb7ec7b..0000000 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "perun-common" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -ckb-std = "0.10.0" -blake2b-rs = "0.2.0" -ckb-standalone-types = { version = "0.1.2", default-features = false, optional = true } -ckb-types = { version = "=0.108.0", optional = true } -k256 = { version = "0.11.6", default-features = false, features = ["ecdsa", "keccak256", "arithmetic"]} -alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } -core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } -buddy-alloc = { version = "0.4.2", optional = true } -ckb-occupied-capacity = { version = "0.108.0", optional = true } - -[dependencies.molecule] -version = "0.7.3" -default-features = false - -[features] -default = ["contract"] -testing = ["std", "ckb-types", "ckb-occupied-capacity"] -std = [] -contract = ["ckb-standalone-types"] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/sig.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/sig.rs deleted file mode 100644 index 3a7e905..0000000 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/sig.rs +++ /dev/null @@ -1,11 +0,0 @@ -use k256::{ecdsa::{VerifyingKey, Signature, signature::{hazmat::PrehashVerifier}}, elliptic_curve::sec1::EncodedPoint, Secp256k1}; - -use crate::error::Error; - -pub fn verify_signature(msg_hash: &[u8; 32], sig: &[u8], key: &[u8]) -> Result<(), Error> { - let signature = Signature::from_der(sig)?; - let e = EncodedPoint::::from_bytes(key).expect("unable to decode public key"); - let verifying_key = VerifyingKey::from_encoded_point(&e)?; - verifying_key.verify_prehash(msg_hash, &signature)?; - Ok(()) -} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml index 6e66cd6..0b9bbe1 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml @@ -3,8 +3,12 @@ name = "perun-funds-lockscript" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -ckb-std = "0.10.0" -perun-common = { path = "../perun-common", default-features = false, features = ["contract"] } +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Makefile b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/README.md b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/README.md new file mode 100644 index 0000000..a58b4e9 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/README.md @@ -0,0 +1,7 @@ +# perun-funds-lockscript + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/entry.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/lib.rs similarity index 78% rename from payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/entry.rs rename to payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/lib.rs index 1d21352..9d3002e 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/entry.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/lib.rs @@ -1,8 +1,11 @@ -// Import from `core` instead of from `std` since we are in no-std mode -use core::result::Result; +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] -// Import heap related library from `alloc` -// https://doc.rust-lang.org/alloc/index.html +use ckb_std::default_alloc; + +ckb_std::entry!(program_entry); +default_alloc!(); use perun_common::error::Error; @@ -14,6 +17,14 @@ use ckb_std::{ high_level::{load_cell_type_hash, load_script, load_transaction}, }; +/// **Main entry point for contract** +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } +} + // The Perun Funds Lock Script can be unlocked by including an input cell with the pcts script hash // that is specified in the args of the pfls. pub fn main() -> Result<(), Error> { diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/main.rs index 9306fc4..42463dc 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/main.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/main.rs @@ -1,32 +1,4 @@ -//! Generated by capsule -//! -//! `main.rs` is used to define rust lang items and modules. -//! See `entry.rs` for the `main` function. -//! See `error.rs` for the `Error` type. +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] -#![no_std] -#![no_main] -#![feature(asm_sym)] -#![feature(lang_items)] -#![feature(alloc_error_handler)] -#![feature(panic_info_message)] - -// define modules -mod entry; - -use ckb_std::default_alloc; -use core::arch::asm; - -ckb_std::entry!(program_entry); -default_alloc!(); - -/// program entry -/// -/// Both `argc` and `argv` can be omitted. -fn program_entry(_argc: u64, _argv: *const *const u8) -> i8 { - // Call main function and return error code - match entry::main() { - Ok(_) => 0, - Err(err) => err as i8, - } -} +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Cargo.toml new file mode 100644 index 0000000..d5d183e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "perun-vchannel-lockscript" +version = "0.1.0" +edition = "2021" + +[dependencies] +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Makefile b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/README.md b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/README.md new file mode 100644 index 0000000..ebfa2bd --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/README.md @@ -0,0 +1,7 @@ +# perun-vchannel-lockscript + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/lib.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/lib.rs new file mode 100644 index 0000000..7e04a2c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/lib.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] + +use ckb_std::default_alloc; + +ckb_std::entry!(program_entry); +default_alloc!(); + +use perun_common::error::Error; + +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } +} + +pub fn main() -> Result<(), Error> { + Ok(()) +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/main.rs new file mode 100644 index 0000000..42463dc --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-lockscript/src/main.rs @@ -0,0 +1,4 @@ +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] + +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Cargo.toml new file mode 100644 index 0000000..e32ae2d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "perun-vchannel-typescript" +version = "0.1.0" +edition = "2021" + + +[dependencies] +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Makefile b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/README.md b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/README.md new file mode 100644 index 0000000..f148827 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/README.md @@ -0,0 +1,7 @@ +# perun-vchannel-typescript + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/lib.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/lib.rs new file mode 100644 index 0000000..2ea5098 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/lib.rs @@ -0,0 +1,754 @@ +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] + +use ckb_std::default_alloc; + +ckb_std::entry!(program_entry); +default_alloc!(); +use alloc::vec; +use core::iter::IntoIterator; +use core::{result::Result, usize}; + +use ckb_std::{ + ckb_constants::Source, + ckb_types::{bytes::Bytes, packed::Byte32, prelude::*}, + debug, + high_level::{ + load_cell_capacity, load_cell_data, load_cell_lock_hash, load_cell_type_hash, load_header, + load_script, load_script_hash, load_witness_args, QueryIter, + }, + syscalls::SysError, +}; + +use perun_common::{ + channels::{find_cell_by_type_hash, unpack_byte32, VChannelAction}, + error::Error, + helpers::blake2b256, + perun_types::{ + Balances, ChannelParameters, ChannelState, ChannelStatus, ChannelWitness, + ChannelWitnessUnion, Participant, SEC1EncodedPubKey, VCChannelConstants, + VirtualChannelStatus, + }, + sig::verify_signature, +}; +use perun_common::sig::ethereum_message_hash; + +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } +} + +pub fn main() -> Result<(), Error> { + debug!("VCTS"); + let script = load_script()?; + let args: Bytes = script.args().unpack(); + if args.is_empty() { + return Err(Error::NoArgs); + } + let channel_constants = + VCChannelConstants::from_slice(&args).expect("unable to parse args as ChannelParams"); + debug!("parsing channel parameters passed"); + + // Verify that the channel parameters are compatible with the currently supported + // features of perun channels. + verify_vchannel_params_compatibility(&channel_constants.params())?; + debug!("verify_channel_params_compatibility passed"); + + // Next, we determine whether the transaction starts, progresses or closes the channel and fetch + // the respective old and/or new channel status. + let channel_action = get_vchannel_action()?; + debug!("get_channel_action passed"); + + match channel_action { + VChannelAction::Start { + new_vc_status, + old_lc_status, + new_lc_status, + } => { + debug!("Start action detected"); + check_valid_vc_start( + &old_lc_status, + &new_lc_status, + &new_vc_status, + &channel_constants, + ) + } + VChannelAction::Progress { + old_status, + new_status, + } => check_valid_vc_progress(&old_status, &new_status, &channel_constants), + VChannelAction::Merge { + input_vc_status1, + input_vc_status2, + merged_vc_status, + } => { + debug!("Merge Tx detected"); + check_valid_vc_merge(&input_vc_status1, &input_vc_status2, &merged_vc_status) + } + + VChannelAction::Close1 { + input_vc_status, + output_vc_status, + } => { + debug!("Close1 Tx detected"); + check_valid_close1(&input_vc_status, &output_vc_status, &channel_constants) + } + + VChannelAction::Close2 { + input_lc_status, + input_vc_status, + } => { + debug!("Close2 Tx detected"); + check_valid_close2(&input_lc_status, &input_vc_status, &channel_constants) + } + } +} + +pub fn check_valid_vc_start( + _: &ChannelStatus, + _: &ChannelStatus, + new_vc_status: &VirtualChannelStatus, + vc_channel_constants: &VCChannelConstants, +) -> Result<(), Error> { + debug!("check_valid_vc_start"); + + //channel_id is the hash of channel parameters + let vc_chanid = new_vc_status.vcstate().channel_id(); + verify_vchannel_id_integrity(&vc_chanid, &vc_channel_constants.params())?; + debug!("verify_channel_id_integrity passed"); + + //validate newly created vc state + verify_vc_sigs_start(&new_vc_status, &vc_channel_constants.params())?; + debug!("verify_vc_sigs passed"); + + //verify that FirstForceCloseFlag is not set + verify_first_forced_closed_flag_not_set(&new_vc_status)?; + + //verify that the lock script is always success lock-script + verify_always_success_lock_script(vc_channel_constants)?; + debug!("verify_always_success_lock_script passed"); + + //verify that the owner lock hash is correctly set + verify_owner_lock(&new_vc_status.owner())?; + // verify that there is only one and the same parent lc cell in inputs and outputs + verify_max_one_parent(&new_vc_status)?; + debug!("verify_max_one_parent passed"); + + Ok(()) +} + +pub fn verify_owner_lock(owner: &Participant) -> Result<(), Error> { + let owner_lock_hash: [u8; 32] = owner.payment_script_hash().unpack(); + let matches: vec::Vec = QueryIter::new(load_cell_lock_hash, Source::Input) + .enumerate() + .filter_map(|(idx, hash)| { + if hash == owner_lock_hash { + Some(idx) + } else { + None + } + }) + .collect(); + + match matches.len() { + 0 => return Err(Error::InvalidVCTxStart), //Input should contain at least cell belonging to owner + _ => (), + }; + Ok(()) +} + +pub fn check_valid_vc_progress( + old_vc_status: &VirtualChannelStatus, + new_vc_status: &VirtualChannelStatus, + vc_constants: &VCChannelConstants, +) -> Result<(), Error> { + debug!("check_valid_vc_progress"); + verify_equal_channel_id_vc(old_vc_status, new_vc_status)?; + debug!("verify_equal_channel_id_vc passed"); + + verify_first_forced_closed_flag_not_set(new_vc_status)?; + debug!("verify_first_forced_closed_flag_not_set passed"); + + verify_non_decreasing_version_number_vc(old_vc_status, new_vc_status)?; + debug!("verify_non_decreasing_version_number_vc passed"); + + let old_vc_state_version: u64 = old_vc_status.vcstate().version().unpack(); + let new_vc_state_version: u64 = new_vc_status.vcstate().version().unpack(); + if old_vc_state_version < new_vc_state_version { + debug!("vc state version number is increasing"); + verify_vc_sigs_progress(new_vc_status, &vc_constants.params())?; + debug!("verify_vc_sigs_progress passed"); + verify_equal_sum_of_balances( + &old_vc_status.vcstate().balances(), + &new_vc_status.vcstate().balances(), + )?; + debug!("verify_equal_sum_of_balances passed"); + } + if old_vc_state_version == new_vc_state_version { + verify_equal_vc_status(old_vc_status, new_vc_status)?; + debug!("verify_equal_channel_state passed"); + } + + debug!("verify_valid_vc_progress passed"); + Ok(()) +} + +pub fn check_valid_vc_merge( + input_vc_stats1: &VirtualChannelStatus, + input_vc_stats2: &VirtualChannelStatus, + merged_vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + debug!("check_valid_vc_merge"); + // 1. We take the vc cell that was created first i.e., lower block number + let vc_cell1_block_num: u64 = load_header(0, Source::GroupInput)?.raw().number().unpack(); + debug!("vc_cell1_block_num: {:?}", vc_cell1_block_num); + let vc_cell2_block_num: u64 = load_header(1, Source::GroupInput)?.raw().number().unpack(); + debug!("vc_cell2_block_num: {:?}", vc_cell2_block_num); + + let selected_vc_cell; + let discarded_vc_cell; + if vc_cell1_block_num < vc_cell2_block_num { + selected_vc_cell = Some(input_vc_stats1); + discarded_vc_cell = Some(input_vc_stats2); + } else if vc_cell1_block_num > vc_cell2_block_num { + selected_vc_cell = Some(input_vc_stats2); + discarded_vc_cell = Some(input_vc_stats1); + } else if vc_cell1_block_num == vc_cell2_block_num { + selected_vc_cell = Some(input_vc_stats1); + discarded_vc_cell = Some(input_vc_stats2); + } else { + return Err(Error::InvalidVCMergeTx); + } + debug!("selected the block with lower block number"); + + verify_equal_vc_status(selected_vc_cell.unwrap(), merged_vc_status)?; + debug!("verify_equal_vc_status passed"); + + // funds put up for the vc cell being removed from chain should be returned to owner + verify_vc_rent_payout_merge(&discarded_vc_cell.unwrap().owner())?; + debug!("verify_vc_rent_payout_merge passed"); + + debug!("check_valid_vc_merge passed"); + Ok(()) +} + +pub fn check_valid_close1( + input_vc_status: &VirtualChannelStatus, + output_vc_status: &VirtualChannelStatus, + _: &VCChannelConstants, +) -> Result<(), Error> { + debug!("check_valid_close1"); + // a parent pcts must appear as input + let parent_input_idx = match get_parent_of_vc(input_vc_status, Source::Input) { + Ok(idx) => idx, + Err(e) => return Err(e), + }; + // parent lc cell is in forceClose Operation + verify_parent_in_force_close(parent_input_idx)?; + debug!("verify_parent_in_force_close passed"); + + //first force close flag is set in output vc cell + verify_first_forced_closed_flag_set(output_vc_status)?; + debug!("verify first force close flag set passed"); + + // all othe fields except first force close flag are equal + if input_vc_status.parents().as_slice() != output_vc_status.parents().as_slice() + && input_vc_status.vcstate().as_slice() != output_vc_status.vcstate().as_slice() + { + return Err(Error::InvalidVCClose1Tx); + } + Ok(()) +} + +pub fn check_valid_close2( + _input_lc_status: &ChannelStatus, + input_vc_status: &VirtualChannelStatus, + _vc_constants: &VCChannelConstants, +) -> Result<(), Error> { + let parent_input_idx = match get_parent_of_vc(input_vc_status, Source::Input) { + Ok(idx) => idx, + Err(e) => return Err(e), + }; + // parent lc cell is in forceClose Operation + verify_parent_in_force_close(parent_input_idx)?; + debug!("verify_parent_in_force_close passed"); + + //first force close flag is set in input vc cell + verify_first_forced_closed_flag_set(input_vc_status)?; + debug!("verify first force close flag set passed"); + + // verify that the output contains a payout cell for the participant, which created vc cell + verify_vc_rent_payout_close2(&input_vc_status.owner())?; + debug!("verify_vc_rent_payout_cell passed"); + Ok(()) +} + +pub fn verify_vc_rent_payout_close2(owner: &Participant) -> Result<(), Error> { + let owner_lock_hash: [u8; 32] = owner.payment_script_hash().unpack(); + let vc_cell_capacity = load_cell_capacity(0, Source::GroupInput)?; + + let matches: vec::Vec = QueryIter::new(load_cell_lock_hash, Source::Output) + .enumerate() + .filter_map(|(idx, hash)| { + if hash == owner_lock_hash { + Some(idx) + } else { + None + } + }) + .collect(); + + if matches.len() == 0 { + return Err(Error::NoVCRentPayoutCell); + } + + let mut total_capacity = 0; + for idx in matches.iter() { + let output_capacity = load_cell_capacity(*idx, Source::Output)?; + total_capacity += output_capacity; + } + + debug!("vc cell capacity: {:?}", vc_cell_capacity); + debug!("total output capacity: {:?}", total_capacity); + + if vc_cell_capacity > total_capacity { + return Err(Error::InvalidVCRentPayoutCell); + } + Ok(()) +} + +pub fn verify_vc_rent_payout_merge(owner: &Participant) -> Result<(), Error> { + let owner_lock_hash: [u8; 32] = owner.payment_script_hash().unpack(); + let vc_cell_capacity = load_cell_capacity(0, Source::GroupInput)?; + + let matches: vec::Vec = QueryIter::new(load_cell_lock_hash, Source::Output) + .enumerate() + .filter_map(|(idx, hash)| { + if hash == owner_lock_hash { + Some(idx) + } else { + None + } + }) + .collect(); + + let output_idx = match matches.len() { + 1 => matches.get(0).unwrap(), + _ => return Err(Error::NoVCRentPayoutCell), //output shoud contain exactly one payout cell + }; + + let output_capacity = load_cell_capacity(output_idx.clone(), Source::Output)?; + debug!("vc cell capacity: {:?}", vc_cell_capacity); + debug!("output_capacity: {:?}", output_capacity); + + if vc_cell_capacity != output_capacity { + return Err(Error::InvalidVCRentPayoutCell); + } + Ok(()) +} + +// two vc statuses are considered equal if all their fields except owner is identical +pub fn verify_equal_vc_status( + input_vc_status: &VirtualChannelStatus, + merged_vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + if input_vc_status.vcstate().as_slice() != merged_vc_status.vcstate().as_slice() { + return Err(Error::InvalidVCMergeTx); + } + + if input_vc_status.parents().as_slice() != merged_vc_status.parents().as_slice() { + return Err(Error::InvalidVCMergeTx); + } + + if input_vc_status.first_force_close().as_slice() + != merged_vc_status.first_force_close().as_slice() + { + return Err(Error::InvalidVCMergeTx); + } + Ok(()) +} + +pub fn verify_always_success_lock_script(vc_constants: &VCChannelConstants) -> Result<(), Error> { + let lock_script_hash = load_cell_lock_hash(0, Source::GroupOutput)?; + if lock_script_hash != vc_constants.vcls_code_hash().as_slice() { + return Err(Error::InvalidVCLockScript); + } + Ok(()) +} + +pub fn verify_first_forced_closed_flag_not_set( + vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + if vc_status.first_force_close().to_bool() { + return Err(Error::FirstForceCloseFlagSet); + } + Ok(()) +} + +pub fn verify_first_forced_closed_flag_set(vc_status: &VirtualChannelStatus) -> Result<(), Error> { + if !vc_status.first_force_close().to_bool() { + debug!("FirstForceCloseFlagNotSet"); + return Err(Error::FirstForceCloseFlagNotSet); + } + Ok(()) +} + +pub fn verify_non_decreasing_version_number_vc( + old_vc_status: &VirtualChannelStatus, + new_vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + let old_vc_state_version: u64 = old_vc_status.vcstate().version().unpack(); + let new_vc_state_version: u64 = new_vc_status.vcstate().version().unpack(); + if old_vc_state_version > new_vc_state_version { + return Err(Error::InvalidVersionNumberVCProgressTx); + } + Ok(()) +} + +pub fn verify_equal_channel_id_vc( + old_vc_status: &VirtualChannelStatus, + new_vc_status: &VirtualChannelStatus, +) -> Result<(), Error> { + let old_vc_state_channel_id: [u8; 32] = old_vc_status.vcstate().channel_id().unpack(); + let new_vc_state_channel_id: [u8; 32] = new_vc_status.vcstate().channel_id().unpack(); + if old_vc_state_channel_id[..] != new_vc_state_channel_id[..] { + return Err(Error::ChannelIdMismatch); + } + Ok(()) +} + +pub fn verify_vc_sigs_start( + new_vc_status: &VirtualChannelStatus, + vc_params: &ChannelParameters, +) -> Result<(), Error> { + let parent_input_idx = match get_parent_of_vc(new_vc_status, Source::Input) { + Ok(idx) => idx, + Err(e) => return Err(e), + }; + let witnes_args = load_witness_args(parent_input_idx, Source::Input)?; + debug!("witness_args loaded"); + let witness_bytes: Bytes = witnes_args + .input_type() + .to_opt() + .ok_or(Error::NoWitness)? + .unpack(); + let witness = ChannelWitness::from_slice(&witness_bytes)?; + let vc_witness = match witness.to_enum() { + ChannelWitnessUnion::VCDispute(vcd) => vcd, + _ => return Err(Error::InvalidVCTxStart), + }; + debug!("VCDispute loaded"); + verify_valid_state_sigs( + &vc_witness.sig_a().unpack(), + &vc_witness.sig_b().unpack(), + &new_vc_status.vcstate(), + &vc_params.party_a().pub_key(), + &vc_params.party_b().pub_key(), + )?; + Ok(()) +} + +pub fn verify_vc_sigs_progress( + new_vc_status: &VirtualChannelStatus, + vc_params: &ChannelParameters, +) -> Result<(), Error> { + let witnes_args = load_witness_args(0, Source::GroupInput)?; + let witness_bytes: Bytes = witnes_args + .input_type() + .to_opt() + .ok_or(Error::NoWitness)? + .unpack(); + + let vc_witness = ChannelWitness::from_slice(&witness_bytes)?; + let vc_sigs = match vc_witness.to_enum() { + ChannelWitnessUnion::Dispute(d) => d, + _ => return Err(Error::InvalidVCTx), + }; + verify_valid_state_sigs( + &vc_sigs.sig_a().unpack(), + &vc_sigs.sig_b().unpack(), + &new_vc_status.vcstate(), + &vc_params.party_a().pub_key(), + &vc_params.party_b().pub_key(), + )?; + Ok(()) +} + +pub fn verify_parent_in_force_close(parent_input_idx: usize) -> Result<(), Error> { + let witnes_args = load_witness_args(parent_input_idx, Source::Input)?; + let witness_bytes: Bytes = witnes_args + .input_type() + .to_opt() + .ok_or(Error::NoWitness)? + .unpack(); + let parent_witness = ChannelWitness::from_slice(&witness_bytes)?; + + match parent_witness.to_enum() { + ChannelWitnessUnion::ForceClose(_) => Ok(()), + _ => Err(Error::ParentNotInForceClose), + } +} + +//checks that only one (and the same) parent ledger channel cell exists in inputs and outputs +pub fn verify_max_one_parent(vc_status: &VirtualChannelStatus) -> Result<(), Error> { + let parent1_hash = match vc_status.parents().get(0) { + Some(parent) => parent.pcts_hash().unpack(), + None => return Err(Error::ParentPCTSHashNotFound), + }; + + let parent2_hash = match vc_status.parents().get(1) { + Some(parent) => parent.pcts_hash().unpack(), + None => return Err(Error::ParentPCTSHashNotFound), + }; + + let hashes = &[(&parent1_hash, "parent1"), (&parent2_hash, "parent2")]; + let mut found_parent = None; + + for (hash, parent) in hashes.iter() { + if let Some(_) = find_cell_by_type_hash(&hash, Source::Input)? { + found_parent = Some(*parent); + break; + } + } + + if let Some(parent) = found_parent { + let parent_hash = if parent == "parent1" { + &parent1_hash + } else { + &parent2_hash + }; + if find_cell_by_type_hash(parent_hash, Source::Output)?.is_none() { + return Err(Error::ParentNotFoundInOutputs); + } + Ok(()) + } else { + Err(Error::InvalidVCTxStart) + } +} + +pub fn verify_valid_state_sigs( + sig_a: &Bytes, + sig_b: &Bytes, + state: &ChannelState, + pub_key_a: &SEC1EncodedPubKey, + pub_key_b: &SEC1EncodedPubKey, +) -> Result<(), Error> { + let msg_hash = ethereum_message_hash(state.as_slice()); + verify_signature(&msg_hash, sig_a, pub_key_a.as_slice())?; + debug!("verify_valid_state_sigs: Signature A verified"); + verify_signature(&msg_hash, sig_b, pub_key_b.as_slice())?; + debug!("verify_valid_state_sigs: Signature B verified"); + Ok(()) +} + +pub fn verify_equal_sum_of_balances( + old_balances: &Balances, + new_balances: &Balances, +) -> Result<(), Error> { + if !old_balances.equal_in_sum(new_balances)? { + return Err(Error::SumOfBalancesNotEqual); + } + Ok(()) +} + +pub fn verify_vchannel_params_compatibility(params: &ChannelParameters) -> Result<(), Error> { + if params.app().to_opt().is_some() { + return Err(Error::AppChannelsNotSupported); + } + if params.is_ledger_channel().to_bool() { + return Err(Error::WrongChannelType); + } + if !params.is_virtual_channel().to_bool() { + return Err(Error::WrongChannelType); + } + Ok(()) +} + +pub fn verify_vchannel_id_integrity( + channel_id: &Byte32, + params: &ChannelParameters, +) -> Result<(), Error> { + let digest = blake2b256(params.as_slice()); + if digest[..] != unpack_byte32(channel_id)[..] { + return Err(Error::InvalidChannelId); + } + Ok(()) +} + +pub fn get_vchannel_action() -> Result { + let mut input_cell_counter = 0; + let mut output_cell_counter = 0; + let max_input_vc_channels = 2; + let vcts_hash = load_script_hash().unwrap(); + for i in 0.. { + let input_cell_hash = match load_cell_type_hash(i, Source::GroupInput) { + Ok(Some(hash)) => hash, + Ok(None) => continue, + Err(SysError::IndexOutOfBound) => break, + Err(_) => return Err(Error::TypeHashNotFound), + }; + if vcts_hash == input_cell_hash { + input_cell_counter += 1; + } + } + for i in 0.. { + let output_cell_hash = match load_cell_type_hash(i, Source::GroupOutput) { + Ok(Some(hash)) => hash, + Ok(None) => continue, + Err(SysError::IndexOutOfBound) => break, + Err(_) => return Err(Error::TypeHashNotFound), + }; + + if vcts_hash == output_cell_hash { + output_cell_counter += 1; + } + } + //MODE: VC Start Tx + if input_cell_counter == 0 && output_cell_counter == 1 { + let vc_status = match load_cell_data(0, Source::GroupOutput) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + // Ok(None) => panic!("Cannot load cell data of vc cell in outputs"), + Err(_) => return Err(Error::UnableToLoadVirtualChannelStatus), + }; + + let parent_input_idx = get_parent_of_vc(&vc_status, Source::Input).unwrap(); + let parent_input_data = match load_cell_data(parent_input_idx, Source::Input) { + Ok(data) => ChannelStatus::from_slice(data.as_slice())?, + Err(_) => return Err(Error::UnableToLoadAnyChannelStatus), + }; + let parent_output_idx = get_parent_of_vc(&vc_status, Source::Output).unwrap(); + let parent_output_data = match load_cell_data(parent_output_idx, Source::Output) { + Ok(data) => ChannelStatus::from_slice(data.as_slice())?, + Err(_) => return Err(Error::UnableToLoadAnyChannelStatus), + }; + + return Ok(VChannelAction::Start { + new_vc_status: vc_status, + old_lc_status: parent_input_data, + new_lc_status: parent_output_data, + }); + + //MODE: VC Merge Tx + } else if input_cell_counter == 2 && output_cell_counter == 1 { + let mut input_vc_statuses: [Option; 2] = [None, None]; + for i in 0..2 { + let vc_status = match load_cell_data(i, Source::GroupInput) { + Ok(data) => { + debug!("VC Status loaded"); + VirtualChannelStatus::from_slice(data.as_slice())? + } + Err(err) => { + debug!("Error loading VC Status"); + return Err(err.into()); + } + }; + + if i < max_input_vc_channels { + input_vc_statuses[i] = Some(vc_status); + } + } + + if input_vc_statuses.iter().all(|status| !status.is_some()) { + return Err(Error::VCInputCellMissingInMergeTx); + } + + let output_vc_status = match load_cell_data(0, Source::GroupOutput) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + + return Ok(VChannelAction::Merge { + input_vc_status1: input_vc_statuses[0].clone().unwrap(), + input_vc_status2: input_vc_statuses[1].clone().unwrap(), + merged_vc_status: output_vc_status, + }); + + //MODE: Either VC Dispute Progress or VC Close 1 + } else if input_cell_counter == 1 && output_cell_counter == 1 { + let input_vc_status = match load_cell_data(0, Source::GroupInput) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + let output_vc_status = match load_cell_data(0, Source::GroupOutput) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + + let parent_input_idx = get_parent_of_vc(&input_vc_status, Source::Input).unwrap(); + let witness_args = load_witness_args(parent_input_idx, Source::Input)?; + let witness_bytes: Bytes = witness_args + .input_type() + .to_opt() + .ok_or(Error::NoWitness)? + .unpack(); + let channel_witness = ChannelWitness::from_slice(&witness_bytes)?; + match channel_witness.to_enum() { + //MODE: VC Progress + ChannelWitnessUnion::Dispute(_) => { + return Ok(VChannelAction::Progress { + old_status: input_vc_status, + new_status: output_vc_status, + }); + } + //MODE: VC Close 1 + ChannelWitnessUnion::ForceClose(_) => { + return Ok(VChannelAction::Close1 { + input_vc_status: input_vc_status, + output_vc_status: output_vc_status, + }); + } + _ => return Err(Error::InvalidVCTx), + } + } else if input_cell_counter == 1 && output_cell_counter == 0 { + //MODE: VC Close 2 + // 1 input parent lc + 1 input vc + // 0 output lc + 0 output vc + let input_vc_status = match load_cell_data(0, Source::GroupInput) { + Ok(data) => VirtualChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + + let parent_input_idx = get_parent_of_vc(&input_vc_status, Source::Input).unwrap(); + let parent_data = match load_cell_data(parent_input_idx, Source::Input) { + Ok(data) => ChannelStatus::from_slice(data.as_slice())?, + Err(err) => return Err(err.into()), + }; + + return Ok(VChannelAction::Close2 { + input_lc_status: parent_data, + input_vc_status: input_vc_status, + }); + } else { + return Err(Error::InvalidVCTx); + } +} + +/// finds either one of the two parents of the virtual channel for the given source +pub fn get_parent_of_vc(vc_status: &VirtualChannelStatus, source: Source) -> Result { + if vc_status.parents().len() != 2 { + return Err(Error::InvalidParentsCountForVC); + } + let parent1_hash = match vc_status.parents().get(0) { + Some(parent) => parent.pcts_hash().unpack(), + None => return Err(Error::ParentPCTSHashNotFound), + }; + + let parent2_hash = match vc_status.parents().get(1) { + Some(parent) => parent.pcts_hash().unpack(), + None => return Err(Error::ParentPCTSHashNotFound), + }; + + let parent_idx = match find_cell_by_type_hash(&parent1_hash, source) { + Ok(Some(i)) => i, + Ok(None) => match find_cell_by_type_hash(&parent2_hash, source) { + Ok(Some(i)) => i, + Ok(None) => return Err(Error::ParentsOfVCNotFound), + Err(err) => return Err(err.into()), + }, + Err(err) => return Err(err.into()), + }; + Ok(parent_idx) +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/main.rs new file mode 100644 index 0000000..42463dc --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-vchannel-typescript/src/main.rs @@ -0,0 +1,4 @@ +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] + +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml index 1d27e95..c6dc941 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml @@ -3,8 +3,12 @@ name = "sample-udt" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -ckb-std = "0.10.0" -perun-common = { path = "../perun-common", default-features = false, features = ["contract"] } +ckb-std = "0.17.0" +perun-common = { path = "../../crates/perun-common", default-features = false, features = ["contract"] } +bytes = { version = "1.0.1", default-features = false } +molecule = { version = "0.8.0", default-features = false, features = ["bytes_vec"] } + +[features] +library = [] +native-simulator = ["library", "ckb-std/native-simulator"] diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Makefile b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/README.md b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/README.md new file mode 100644 index 0000000..9e18d7d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/README.md @@ -0,0 +1,7 @@ +# sample-udt + +TODO: Write this readme + +*This contract was bootstrapped with [ckb-script-templates].* + +[ckb-script-templates]: https://github.com/cryptape/ckb-script-templates diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/lib.rs similarity index 80% rename from payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs rename to payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/lib.rs index 4e0c757..8ad9e04 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/lib.rs @@ -1,17 +1,32 @@ -// Import from `core` instead of from `std` since we are in no-std mode -use core::result::Result; +#![cfg_attr(not(feature = "library"), no_std)] +#![allow(special_module_name)] +#![allow(unused_attributes)] + +use ckb_std::default_alloc; + +ckb_std::entry!(program_entry); +default_alloc!(); // Import CKB syscalls and structures // https://docs.rs/ckb-std/ use ckb_std::{ ckb_constants::Source, ckb_types::{bytes::Bytes, prelude::*}, - high_level::{load_cell_lock_hash, load_script, load_cell_data}, + high_level::{load_cell_data, load_cell_lock_hash, load_script}, syscalls::SysError, }; use perun_common::error::Error; +/// **Main entry point for contract** +pub fn program_entry() -> i8 { + match main() { + Ok(_) => 0, // Success + Err(_) => -1, // Failure + } +} +// The Perun Funds Lock Script can be unlocked by including an input cell with the pcts script hash +// that is specified in the args of the pfls. pub fn main() -> Result<(), Error> { let script = load_script()?; let args: Bytes = script.args().unpack(); @@ -36,17 +51,14 @@ pub fn check_owner_mode(args: &Bytes) -> Result { // current transaction to see if any unlocked cell uses owner lock. for i in 0.. { // check input's lock_hash with script args - let lock_hash = match load_cell_lock_hash( - i, - Source::Input, - ) { + let lock_hash = match load_cell_lock_hash(i, Source::Input) { Ok(lock_hash) => lock_hash, Err(SysError::IndexOutOfBound) => return Ok(false), Err(err) => return Err(err.into()), }; // invalid length of loaded data if args[..] == lock_hash[..] { - return Ok(true); + return Ok(true); } } Ok(false) @@ -98,4 +110,4 @@ fn collect_outputs_amount() -> Result { outputs_amount += u128::from_le_bytes(buf); } Ok(outputs_amount) -} \ No newline at end of file +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/main.rs b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/main.rs index 9306fc4..42463dc 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/main.rs +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/main.rs @@ -1,32 +1,4 @@ -//! Generated by capsule -//! -//! `main.rs` is used to define rust lang items and modules. -//! See `entry.rs` for the `main` function. -//! See `error.rs` for the `Error` type. +#![cfg_attr(not(any(feature = "library", test)), no_std)] +#![cfg_attr(not(test), no_main)] -#![no_std] -#![no_main] -#![feature(asm_sym)] -#![feature(lang_items)] -#![feature(alloc_error_handler)] -#![feature(panic_info_message)] - -// define modules -mod entry; - -use ckb_std::default_alloc; -use core::arch::asm; - -ckb_std::entry!(program_entry); -default_alloc!(); - -/// program entry -/// -/// Both `argc` and `argv` can be omitted. -fn program_entry(_argc: u64, _argv: *const *const u8) -> i8 { - // Call main function and return error code - match entry::main() { - Ok(_) => 0, - Err(err) => err as i8, - } -} +mod lib; diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/Cargo.toml b/payment-channel-ckb/devnet/contracts/crates/perun-common/Cargo.toml new file mode 100644 index 0000000..443c5a3 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "perun-common" +version = "0.1.0" +edition = "2021" + +[lib] # Ensure it's a library +crate-type = ["rlib"] + +[dependencies] +ckb-std = "0.17.0" +blake2b-rs = { version = "0.2.0", default-features = false} +ckb-types = { version = "0.200.0", optional = true } +ckb-gen-types = { version = "0.200.0", default-features = false, optional = true } +k256 = { version = "0.13.4", default-features = false, features = ["ecdsa", "sha256", "arithmetic"]} +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +buddy-alloc = { version = "0.6.0", optional = true } +ckb-occupied-capacity = { version = "0.200.0", optional = true } +sha3 = "0.11.0-pre.4" + +[dependencies.molecule] +version = "0.8.0" +default-features = false +features = ["bytes_vec"] + +[features] +default = ["contract"] +testing = ["std", "ckb-types", "ckb-occupied-capacity"] +std = [] +contract = ["ckb-gen-types"] \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/Makefile b/payment-channel-ckb/devnet/contracts/crates/perun-common/Makefile new file mode 100644 index 0000000..e1112c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/Makefile @@ -0,0 +1,80 @@ +# We cannot use $(shell pwd), which will return unix path format on Windows, +# making it hard to use. +cur_dir = $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) + +TOP := $(cur_dir) +# RUSTFLAGS that are likely to be tweaked by developers. For example, +# while we enable debug logs by default here, some might want to strip them +# for minimal code size / consumed cycles. +CUSTOM_RUSTFLAGS := -C debug-assertions +# RUSTFLAGS that are less likely to be tweaked by developers. Most likely +# one would want to keep the default values here. +FULL_RUSTFLAGS := -C target-feature=+zba,+zbb,+zbc,+zbs,-a $(CUSTOM_RUSTFLAGS) +# Additional cargo args to append here. For example, one can use +# make test CARGO_ARGS="-- --nocapture" so as to inspect data emitted to +# stdout in unit tests +CARGO_ARGS := +MODE := release +# Tweak this to change the clang version to use for building C code. By default +# we use a bash script with somes heuristics to find clang in current system. +CLANG := $(shell $(TOP)/scripts/find_clang) +AR := $(subst clang,llvm-ar,$(CLANG)) +OBJCOPY := $(subst clang,llvm-objcopy,$(CLANG)) +# When this is set to some value, the generated binaries will be copied over +BUILD_DIR := +# Generated binaries to copy. By convention, a Rust crate's directory name will +# likely match the crate name, which is also the name of the final binary. +# However if this is not the case, you can tweak this variable. As the name hints, +# more than one binary is supported here. +BINARIES := $(notdir $(shell pwd)) + +ifeq (release,$(MODE)) + MODE_ARGS := --release +endif + +default: build test + +build: + RUSTFLAGS="$(FULL_RUSTFLAGS)" TARGET_CC="$(CLANG)" TARGET_AR="$(AR)" \ + cargo build --target=riscv64imac-unknown-none-elf $(MODE_ARGS) $(CARGO_ARGS) + @set -eu; \ + if [ "x$(BUILD_DIR)" != "x" ]; then \ + for binary in $(BINARIES); do \ + echo "Copying binary $$binary to build directory"; \ + cp $(TOP)/target/riscv64imac-unknown-none-elf/$(MODE)/$$binary $(TOP)/$(BUILD_DIR); \ + cp $(TOP)/$(BUILD_DIR)/$$binary $(TOP)/$(BUILD_DIR)/$$binary.debug; \ + $(OBJCOPY) --strip-debug --strip-all $(TOP)/$(BUILD_DIR)/$$binary; \ + done \ + fi + +# test, check, clippy and fmt here are provided for completeness, +# there is nothing wrong invoking cargo directly instead of make. +test: + cargo test $(CARGO_ARGS) + +check: + cargo check $(CARGO_ARGS) + +clippy: + cargo clippy $(CARGO_ARGS) + +fmt: + cargo fmt $(CARGO_ARGS) + +# Arbitrary cargo command is supported here. For example: +# +# make cargo CARGO_CMD=expand CARGO_ARGS="--ugly" +# +# Invokes: +# cargo expand --ugly +CARGO_CMD := +cargo: + cargo $(CARGO_CMD) $(CARGO_ARGS) + +clean: + cargo clean + +prepare: + rustup target add riscv64imac-unknown-none-elf + +.PHONY: build test check clippy fmt cargo clean prepare diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/blockchain.mol b/payment-channel-ckb/devnet/contracts/crates/perun-common/blockchain.mol similarity index 100% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/blockchain.mol rename to payment-channel-ckb/devnet/contracts/crates/perun-common/blockchain.mol diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/merged.mol b/payment-channel-ckb/devnet/contracts/crates/perun-common/merged.mol new file mode 100644 index 0000000..192f3c6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/merged.mol @@ -0,0 +1,247 @@ +/* Basic Types */ + +array Uint32 [byte; 4]; +array Uint64 [byte; 8]; +array Uint128 [byte; 16]; +array Byte32 [byte; 32]; +array Uint256 [byte; 32]; + +vector Bytes ; +option BytesOpt (Bytes); + +vector BytesVec ; +vector Byte32Vec ; + +/* Types for Chain */ + +option ScriptOpt (Script); + +array ProposalShortId [byte; 10]; + +vector UncleBlockVec ; +vector TransactionVec ; +vector ProposalShortIdVec ; +vector CellDepVec ; +vector CellInputVec ; +vector CellOutputVec ; + +table Script { + code_hash: Byte32, + hash_type: byte, + args: Bytes, +} + +struct OutPoint { + tx_hash: Byte32, + index: Uint32, +} + +struct CellInput { + since: Uint64, + previous_output: OutPoint, +} + +table CellOutput { + capacity: Uint64, + lock: Script, + type_: ScriptOpt, +} + +struct CellDep { + out_point: OutPoint, + dep_type: byte, +} + +table RawTransaction { + version: Uint32, + cell_deps: CellDepVec, + header_deps: Byte32Vec, + inputs: CellInputVec, + outputs: CellOutputVec, + outputs_data: BytesVec, +} + +table Transaction { + raw: RawTransaction, + witnesses: BytesVec, +} + +struct RawHeader { + version: Uint32, + compact_target: Uint32, + timestamp: Uint64, + number: Uint64, + epoch: Uint64, + parent_hash: Byte32, + transactions_root: Byte32, + proposals_hash: Byte32, + uncles_hash: Byte32, + dao: Byte32, +} + +struct Header { + raw: RawHeader, + nonce: Uint128, +} + +table UncleBlock { + header: Header, + proposals: ProposalShortIdVec, +} + +table Block { + header: Header, + uncles: UncleBlockVec, + transactions: TransactionVec, + proposals: ProposalShortIdVec, +} + +table CellbaseWitness { + lock: Script, + message: Bytes, +} + +table WitnessArgs { + lock: BytesOpt, // Lock args + input_type: BytesOpt, // Type args for input + output_type: BytesOpt, // Type args for output +} + +/* Perun Types */ +array SEC1EncodedPubKey [byte; 33]; + +array CKByteDistribution [Uint64; 2]; + +array SUDTDistribution [Uint128; 2]; + +vector SUDTAllocation ; + +table SUDTAsset { + type_script: Script, + // The max_capacity of an SUDTAsset should always be at least the capacity needed for the SUDT type script + outputs_data + // + max(party_a.payment_min_capacity, party_b.payment_min_capacity) + // Make sure verify this in the Funding Agreement, as the contract can not verify this upon channel start! + max_capacity: Uint64, +} + +table SUDTBalances { + asset: SUDTAsset, + distribution: SUDTDistribution, +} + +table Balances { + ckbytes: CKByteDistribution, + sudts: SUDTAllocation, +} + +array True [byte; 1]; +array False [byte; 1]; + +union Bool { + True, + False, +} + +array A [byte; 1]; +array B [byte; 1]; + + +option App (Bytes); + +// Terminology: +// - script_hash: By script_hash we mean the results of the syscalls load_cell_lock_hash / load_cell_type_hash +// and the sdk function calc_script_hash. This is the hash of the script struct (code_hash, hash_type and args). +// - code_hash: By code_hash we mean the member of a script that hold the hash of the executed code (depending on the hash_type). +// See: https://docs.nervos.org/docs/reference/script/ + + + +table Participant { + // payment_script_hash specifies the script-hash used + // to lock payments to this participant (upon channel close) + payment_script_hash: Byte32, + // payment_min_capacity specifies the minimum capacity of the payment lock script. + payment_min_capacity: Uint64, + + // unlock_script_hash specifies the script-hash that needs to be present in the inputs + // to a transaction to authorize the transaction to interact with the channel as + // this channel participant. + unlock_script_hash: Byte32, + + pub_key: SEC1EncodedPubKey, +} +table ChannelParameters { + party_a: Participant, + party_b: Participant, + nonce: Byte32, + challenge_duration: Uint64, + // The default should be NoApp! + app: App, + // This should always be set to true for, as we currently only support ledger channels. + is_ledger_channel: Bool, + // This should always be set to false for, as we currently do not support virtual channels. + is_virtual_channel: Bool, +} + +// Important: Upon channel creation, every participant must verify the integrity of the channel. +// This includes verifying that the correct ChannelConstants are present. +// If e.g. the payment_min_capacity (inside the participants of the channel parameters) were to be significantly larger than the minimum +// capacity of the payment lock script, a party could steal funds from the channel participants with balances smaller than the +// payment_min_capacity upon channel closing. +table ChannelConstants { + params: ChannelParameters, + // pfls__code_hash specifies the code hash of the lock_script that guards funds for this channel. + // Specifically, this should be the perun-funds-lockscript. + pfls_code_hash: Byte32, + pfls_hash_type: byte, + pfls_min_capacity: Uint64, + + // pcls_hash specifies the lock_script used for this channel. + // Specifically, this should be the perun-channel-lockscript. + pcls_code_hash: Byte32, + pcls_hash_type: byte, + + thread_token: ChannelToken, +} + +array Fund [byte; 1]; + +array Abort [byte; 1]; + +table Dispute { + sig_a: Bytes, + sig_b: Bytes, +} +table Close { + state: ChannelState, + sig_a: Bytes, + sig_b: Bytes, +} +array ForceClose [byte; 1]; + + +union ChannelWitness { + Fund, + Abort, + Dispute, + Close, + ForceClose, +} + +table ChannelState { + // + channel_id: Byte32, + balances: Balances, + version: Uint64, + is_final: Bool, +} + +table ChannelStatus { + state: ChannelState, + funded: Bool, + disputed: Bool, +} + +struct ChannelToken { + out_point: OutPoint, +} \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/offchain_types.mol b/payment-channel-ckb/devnet/contracts/crates/perun-common/offchain_types.mol similarity index 100% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/offchain_types.mol rename to payment-channel-ckb/devnet/contracts/crates/perun-common/offchain_types.mol diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/src/blockchain_types.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/blockchain_types.rs new file mode 100644 index 0000000..beeaf01 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/blockchain_types.rs @@ -0,0 +1,119 @@ +// Generated by Molecule 0.8.0 + +use molecule :: prelude :: * ; +# [derive (Clone)] pub struct Uint32 (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Uint32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Uint32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Uint32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Uint32 { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Uint32 :: new_unchecked (v) } } impl Uint32 { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 4 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 4 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> Uint32Reader < 'r > { Uint32Reader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Uint32 { type Builder = Uint32Builder ; const NAME : & 'static str = "Uint32" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Uint32 (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint32Reader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint32Reader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () ,]) } } +# [derive (Clone , Copy)] pub struct Uint32Reader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Uint32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Uint32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Uint32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > Uint32Reader < 'r > { pub const TOTAL_SIZE : usize = 4 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 4 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for Uint32Reader < 'r > { type Entity = Uint32 ; const NAME : & 'static str = "Uint32Reader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Uint32Reader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct Uint32Builder (pub (crate) [Byte ; 4]) ; impl :: core :: fmt :: Debug for Uint32Builder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for Uint32Builder { fn default () -> Self { Uint32Builder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl Uint32Builder { pub const TOTAL_SIZE : usize = 4 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 4 ; pub fn set (mut self , v : [Byte ; 4]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } } impl molecule :: prelude :: Builder for Uint32Builder { type Entity = Uint32 ; const NAME : & 'static str = "Uint32Builder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Uint32 :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 4usize] > for Uint32 { fn from (value : [Byte ; 4usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for Uint32 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 4usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < Uint32 > for [Byte ; 4usize] { # [track_caller] fn from (value : Uint32) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () ,] } } impl From < [u8 ; 4usize] > for Uint32 { fn from (value : [u8 ; 4usize]) -> Self { Uint32Reader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for Uint32 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 4usize] > :: try_from (value) ? . into ()) } } impl From < Uint32 > for [u8 ; 4usize] { # [track_caller] fn from (value : Uint32) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < Uint32Reader < 'a >> for & 'a [u8 ; 4usize] { # [track_caller] fn from (value : Uint32Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a Uint32Reader < 'a >> for & 'a [u8 ; 4usize] { # [track_caller] fn from (value : & 'a Uint32Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct Uint64 (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Uint64 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Uint64 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Uint64 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Uint64 { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Uint64 :: new_unchecked (v) } } impl Uint64 { const DEFAULT_VALUE : [u8 ; 8] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 8 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 8 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn nth4 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (4 .. 5)) } pub fn nth5 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (5 .. 6)) } pub fn nth6 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (6 .. 7)) } pub fn nth7 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (7 .. 8)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> Uint64Reader < 'r > { Uint64Reader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Uint64 { type Builder = Uint64Builder ; const NAME : & 'static str = "Uint64" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Uint64 (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint64Reader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint64Reader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () , self . nth4 () , self . nth5 () , self . nth6 () , self . nth7 () ,]) } } +# [derive (Clone , Copy)] pub struct Uint64Reader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Uint64Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Uint64Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Uint64Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > Uint64Reader < 'r > { pub const TOTAL_SIZE : usize = 8 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 8 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn nth4 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [4 .. 5]) } pub fn nth5 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [5 .. 6]) } pub fn nth6 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [6 .. 7]) } pub fn nth7 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [7 .. 8]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for Uint64Reader < 'r > { type Entity = Uint64 ; const NAME : & 'static str = "Uint64Reader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Uint64Reader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct Uint64Builder (pub (crate) [Byte ; 8]) ; impl :: core :: fmt :: Debug for Uint64Builder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for Uint64Builder { fn default () -> Self { Uint64Builder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl Uint64Builder { pub const TOTAL_SIZE : usize = 8 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 8 ; pub fn set (mut self , v : [Byte ; 8]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } pub fn nth4 (mut self , v : Byte) -> Self { self . 0 [4] = v ; self } pub fn nth5 (mut self , v : Byte) -> Self { self . 0 [5] = v ; self } pub fn nth6 (mut self , v : Byte) -> Self { self . 0 [6] = v ; self } pub fn nth7 (mut self , v : Byte) -> Self { self . 0 [7] = v ; self } } impl molecule :: prelude :: Builder for Uint64Builder { type Entity = Uint64 ; const NAME : & 'static str = "Uint64Builder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; writer . write_all (self . 0 [4] . as_slice ()) ? ; writer . write_all (self . 0 [5] . as_slice ()) ? ; writer . write_all (self . 0 [6] . as_slice ()) ? ; writer . write_all (self . 0 [7] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Uint64 :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 8usize] > for Uint64 { fn from (value : [Byte ; 8usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for Uint64 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 8usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < Uint64 > for [Byte ; 8usize] { # [track_caller] fn from (value : Uint64) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () , value . nth4 () , value . nth5 () , value . nth6 () , value . nth7 () ,] } } impl From < [u8 ; 8usize] > for Uint64 { fn from (value : [u8 ; 8usize]) -> Self { Uint64Reader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for Uint64 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 8usize] > :: try_from (value) ? . into ()) } } impl From < Uint64 > for [u8 ; 8usize] { # [track_caller] fn from (value : Uint64) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < Uint64Reader < 'a >> for & 'a [u8 ; 8usize] { # [track_caller] fn from (value : Uint64Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a Uint64Reader < 'a >> for & 'a [u8 ; 8usize] { # [track_caller] fn from (value : & 'a Uint64Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct Uint128 (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Uint128 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Uint128 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Uint128 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Uint128 { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Uint128 :: new_unchecked (v) } } impl Uint128 { const DEFAULT_VALUE : [u8 ; 16] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 16 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 16 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn nth4 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (4 .. 5)) } pub fn nth5 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (5 .. 6)) } pub fn nth6 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (6 .. 7)) } pub fn nth7 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (7 .. 8)) } pub fn nth8 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (8 .. 9)) } pub fn nth9 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (9 .. 10)) } pub fn nth10 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (10 .. 11)) } pub fn nth11 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (11 .. 12)) } pub fn nth12 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (12 .. 13)) } pub fn nth13 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (13 .. 14)) } pub fn nth14 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (14 .. 15)) } pub fn nth15 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (15 .. 16)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> Uint128Reader < 'r > { Uint128Reader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Uint128 { type Builder = Uint128Builder ; const NAME : & 'static str = "Uint128" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Uint128 (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint128Reader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint128Reader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () , self . nth4 () , self . nth5 () , self . nth6 () , self . nth7 () , self . nth8 () , self . nth9 () , self . nth10 () , self . nth11 () , self . nth12 () , self . nth13 () , self . nth14 () , self . nth15 () ,]) } } +# [derive (Clone , Copy)] pub struct Uint128Reader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Uint128Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Uint128Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Uint128Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > Uint128Reader < 'r > { pub const TOTAL_SIZE : usize = 16 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 16 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn nth4 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [4 .. 5]) } pub fn nth5 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [5 .. 6]) } pub fn nth6 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [6 .. 7]) } pub fn nth7 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [7 .. 8]) } pub fn nth8 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [8 .. 9]) } pub fn nth9 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [9 .. 10]) } pub fn nth10 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [10 .. 11]) } pub fn nth11 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [11 .. 12]) } pub fn nth12 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [12 .. 13]) } pub fn nth13 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [13 .. 14]) } pub fn nth14 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [14 .. 15]) } pub fn nth15 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [15 .. 16]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for Uint128Reader < 'r > { type Entity = Uint128 ; const NAME : & 'static str = "Uint128Reader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Uint128Reader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct Uint128Builder (pub (crate) [Byte ; 16]) ; impl :: core :: fmt :: Debug for Uint128Builder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for Uint128Builder { fn default () -> Self { Uint128Builder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl Uint128Builder { pub const TOTAL_SIZE : usize = 16 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 16 ; pub fn set (mut self , v : [Byte ; 16]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } pub fn nth4 (mut self , v : Byte) -> Self { self . 0 [4] = v ; self } pub fn nth5 (mut self , v : Byte) -> Self { self . 0 [5] = v ; self } pub fn nth6 (mut self , v : Byte) -> Self { self . 0 [6] = v ; self } pub fn nth7 (mut self , v : Byte) -> Self { self . 0 [7] = v ; self } pub fn nth8 (mut self , v : Byte) -> Self { self . 0 [8] = v ; self } pub fn nth9 (mut self , v : Byte) -> Self { self . 0 [9] = v ; self } pub fn nth10 (mut self , v : Byte) -> Self { self . 0 [10] = v ; self } pub fn nth11 (mut self , v : Byte) -> Self { self . 0 [11] = v ; self } pub fn nth12 (mut self , v : Byte) -> Self { self . 0 [12] = v ; self } pub fn nth13 (mut self , v : Byte) -> Self { self . 0 [13] = v ; self } pub fn nth14 (mut self , v : Byte) -> Self { self . 0 [14] = v ; self } pub fn nth15 (mut self , v : Byte) -> Self { self . 0 [15] = v ; self } } impl molecule :: prelude :: Builder for Uint128Builder { type Entity = Uint128 ; const NAME : & 'static str = "Uint128Builder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; writer . write_all (self . 0 [4] . as_slice ()) ? ; writer . write_all (self . 0 [5] . as_slice ()) ? ; writer . write_all (self . 0 [6] . as_slice ()) ? ; writer . write_all (self . 0 [7] . as_slice ()) ? ; writer . write_all (self . 0 [8] . as_slice ()) ? ; writer . write_all (self . 0 [9] . as_slice ()) ? ; writer . write_all (self . 0 [10] . as_slice ()) ? ; writer . write_all (self . 0 [11] . as_slice ()) ? ; writer . write_all (self . 0 [12] . as_slice ()) ? ; writer . write_all (self . 0 [13] . as_slice ()) ? ; writer . write_all (self . 0 [14] . as_slice ()) ? ; writer . write_all (self . 0 [15] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Uint128 :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 16usize] > for Uint128 { fn from (value : [Byte ; 16usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for Uint128 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 16usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < Uint128 > for [Byte ; 16usize] { # [track_caller] fn from (value : Uint128) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () , value . nth4 () , value . nth5 () , value . nth6 () , value . nth7 () , value . nth8 () , value . nth9 () , value . nth10 () , value . nth11 () , value . nth12 () , value . nth13 () , value . nth14 () , value . nth15 () ,] } } impl From < [u8 ; 16usize] > for Uint128 { fn from (value : [u8 ; 16usize]) -> Self { Uint128Reader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for Uint128 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 16usize] > :: try_from (value) ? . into ()) } } impl From < Uint128 > for [u8 ; 16usize] { # [track_caller] fn from (value : Uint128) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < Uint128Reader < 'a >> for & 'a [u8 ; 16usize] { # [track_caller] fn from (value : Uint128Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a Uint128Reader < 'a >> for & 'a [u8 ; 16usize] { # [track_caller] fn from (value : & 'a Uint128Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct Byte32 (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Byte32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Byte32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Byte32 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Byte32 { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Byte32 :: new_unchecked (v) } } impl Byte32 { const DEFAULT_VALUE : [u8 ; 32] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn nth4 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (4 .. 5)) } pub fn nth5 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (5 .. 6)) } pub fn nth6 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (6 .. 7)) } pub fn nth7 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (7 .. 8)) } pub fn nth8 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (8 .. 9)) } pub fn nth9 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (9 .. 10)) } pub fn nth10 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (10 .. 11)) } pub fn nth11 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (11 .. 12)) } pub fn nth12 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (12 .. 13)) } pub fn nth13 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (13 .. 14)) } pub fn nth14 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (14 .. 15)) } pub fn nth15 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (15 .. 16)) } pub fn nth16 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (16 .. 17)) } pub fn nth17 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (17 .. 18)) } pub fn nth18 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (18 .. 19)) } pub fn nth19 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (19 .. 20)) } pub fn nth20 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (20 .. 21)) } pub fn nth21 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (21 .. 22)) } pub fn nth22 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (22 .. 23)) } pub fn nth23 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (23 .. 24)) } pub fn nth24 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (24 .. 25)) } pub fn nth25 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (25 .. 26)) } pub fn nth26 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (26 .. 27)) } pub fn nth27 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (27 .. 28)) } pub fn nth28 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (28 .. 29)) } pub fn nth29 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (29 .. 30)) } pub fn nth30 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (30 .. 31)) } pub fn nth31 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (31 .. 32)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Byte32 { type Builder = Byte32Builder ; const NAME : & 'static str = "Byte32" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Byte32 (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Byte32Reader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Byte32Reader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () , self . nth4 () , self . nth5 () , self . nth6 () , self . nth7 () , self . nth8 () , self . nth9 () , self . nth10 () , self . nth11 () , self . nth12 () , self . nth13 () , self . nth14 () , self . nth15 () , self . nth16 () , self . nth17 () , self . nth18 () , self . nth19 () , self . nth20 () , self . nth21 () , self . nth22 () , self . nth23 () , self . nth24 () , self . nth25 () , self . nth26 () , self . nth27 () , self . nth28 () , self . nth29 () , self . nth30 () , self . nth31 () ,]) } } +# [derive (Clone , Copy)] pub struct Byte32Reader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Byte32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Byte32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Byte32Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > Byte32Reader < 'r > { pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn nth4 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [4 .. 5]) } pub fn nth5 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [5 .. 6]) } pub fn nth6 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [6 .. 7]) } pub fn nth7 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [7 .. 8]) } pub fn nth8 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [8 .. 9]) } pub fn nth9 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [9 .. 10]) } pub fn nth10 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [10 .. 11]) } pub fn nth11 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [11 .. 12]) } pub fn nth12 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [12 .. 13]) } pub fn nth13 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [13 .. 14]) } pub fn nth14 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [14 .. 15]) } pub fn nth15 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [15 .. 16]) } pub fn nth16 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [16 .. 17]) } pub fn nth17 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [17 .. 18]) } pub fn nth18 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [18 .. 19]) } pub fn nth19 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [19 .. 20]) } pub fn nth20 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [20 .. 21]) } pub fn nth21 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [21 .. 22]) } pub fn nth22 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [22 .. 23]) } pub fn nth23 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [23 .. 24]) } pub fn nth24 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [24 .. 25]) } pub fn nth25 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [25 .. 26]) } pub fn nth26 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [26 .. 27]) } pub fn nth27 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [27 .. 28]) } pub fn nth28 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [28 .. 29]) } pub fn nth29 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [29 .. 30]) } pub fn nth30 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [30 .. 31]) } pub fn nth31 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [31 .. 32]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for Byte32Reader < 'r > { type Entity = Byte32 ; const NAME : & 'static str = "Byte32Reader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Byte32Reader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct Byte32Builder (pub (crate) [Byte ; 32]) ; impl :: core :: fmt :: Debug for Byte32Builder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for Byte32Builder { fn default () -> Self { Byte32Builder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl Byte32Builder { pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn set (mut self , v : [Byte ; 32]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } pub fn nth4 (mut self , v : Byte) -> Self { self . 0 [4] = v ; self } pub fn nth5 (mut self , v : Byte) -> Self { self . 0 [5] = v ; self } pub fn nth6 (mut self , v : Byte) -> Self { self . 0 [6] = v ; self } pub fn nth7 (mut self , v : Byte) -> Self { self . 0 [7] = v ; self } pub fn nth8 (mut self , v : Byte) -> Self { self . 0 [8] = v ; self } pub fn nth9 (mut self , v : Byte) -> Self { self . 0 [9] = v ; self } pub fn nth10 (mut self , v : Byte) -> Self { self . 0 [10] = v ; self } pub fn nth11 (mut self , v : Byte) -> Self { self . 0 [11] = v ; self } pub fn nth12 (mut self , v : Byte) -> Self { self . 0 [12] = v ; self } pub fn nth13 (mut self , v : Byte) -> Self { self . 0 [13] = v ; self } pub fn nth14 (mut self , v : Byte) -> Self { self . 0 [14] = v ; self } pub fn nth15 (mut self , v : Byte) -> Self { self . 0 [15] = v ; self } pub fn nth16 (mut self , v : Byte) -> Self { self . 0 [16] = v ; self } pub fn nth17 (mut self , v : Byte) -> Self { self . 0 [17] = v ; self } pub fn nth18 (mut self , v : Byte) -> Self { self . 0 [18] = v ; self } pub fn nth19 (mut self , v : Byte) -> Self { self . 0 [19] = v ; self } pub fn nth20 (mut self , v : Byte) -> Self { self . 0 [20] = v ; self } pub fn nth21 (mut self , v : Byte) -> Self { self . 0 [21] = v ; self } pub fn nth22 (mut self , v : Byte) -> Self { self . 0 [22] = v ; self } pub fn nth23 (mut self , v : Byte) -> Self { self . 0 [23] = v ; self } pub fn nth24 (mut self , v : Byte) -> Self { self . 0 [24] = v ; self } pub fn nth25 (mut self , v : Byte) -> Self { self . 0 [25] = v ; self } pub fn nth26 (mut self , v : Byte) -> Self { self . 0 [26] = v ; self } pub fn nth27 (mut self , v : Byte) -> Self { self . 0 [27] = v ; self } pub fn nth28 (mut self , v : Byte) -> Self { self . 0 [28] = v ; self } pub fn nth29 (mut self , v : Byte) -> Self { self . 0 [29] = v ; self } pub fn nth30 (mut self , v : Byte) -> Self { self . 0 [30] = v ; self } pub fn nth31 (mut self , v : Byte) -> Self { self . 0 [31] = v ; self } } impl molecule :: prelude :: Builder for Byte32Builder { type Entity = Byte32 ; const NAME : & 'static str = "Byte32Builder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; writer . write_all (self . 0 [4] . as_slice ()) ? ; writer . write_all (self . 0 [5] . as_slice ()) ? ; writer . write_all (self . 0 [6] . as_slice ()) ? ; writer . write_all (self . 0 [7] . as_slice ()) ? ; writer . write_all (self . 0 [8] . as_slice ()) ? ; writer . write_all (self . 0 [9] . as_slice ()) ? ; writer . write_all (self . 0 [10] . as_slice ()) ? ; writer . write_all (self . 0 [11] . as_slice ()) ? ; writer . write_all (self . 0 [12] . as_slice ()) ? ; writer . write_all (self . 0 [13] . as_slice ()) ? ; writer . write_all (self . 0 [14] . as_slice ()) ? ; writer . write_all (self . 0 [15] . as_slice ()) ? ; writer . write_all (self . 0 [16] . as_slice ()) ? ; writer . write_all (self . 0 [17] . as_slice ()) ? ; writer . write_all (self . 0 [18] . as_slice ()) ? ; writer . write_all (self . 0 [19] . as_slice ()) ? ; writer . write_all (self . 0 [20] . as_slice ()) ? ; writer . write_all (self . 0 [21] . as_slice ()) ? ; writer . write_all (self . 0 [22] . as_slice ()) ? ; writer . write_all (self . 0 [23] . as_slice ()) ? ; writer . write_all (self . 0 [24] . as_slice ()) ? ; writer . write_all (self . 0 [25] . as_slice ()) ? ; writer . write_all (self . 0 [26] . as_slice ()) ? ; writer . write_all (self . 0 [27] . as_slice ()) ? ; writer . write_all (self . 0 [28] . as_slice ()) ? ; writer . write_all (self . 0 [29] . as_slice ()) ? ; writer . write_all (self . 0 [30] . as_slice ()) ? ; writer . write_all (self . 0 [31] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Byte32 :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 32usize] > for Byte32 { fn from (value : [Byte ; 32usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for Byte32 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 32usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < Byte32 > for [Byte ; 32usize] { # [track_caller] fn from (value : Byte32) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () , value . nth4 () , value . nth5 () , value . nth6 () , value . nth7 () , value . nth8 () , value . nth9 () , value . nth10 () , value . nth11 () , value . nth12 () , value . nth13 () , value . nth14 () , value . nth15 () , value . nth16 () , value . nth17 () , value . nth18 () , value . nth19 () , value . nth20 () , value . nth21 () , value . nth22 () , value . nth23 () , value . nth24 () , value . nth25 () , value . nth26 () , value . nth27 () , value . nth28 () , value . nth29 () , value . nth30 () , value . nth31 () ,] } } impl From < [u8 ; 32usize] > for Byte32 { fn from (value : [u8 ; 32usize]) -> Self { Byte32Reader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for Byte32 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 32usize] > :: try_from (value) ? . into ()) } } impl From < Byte32 > for [u8 ; 32usize] { # [track_caller] fn from (value : Byte32) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < Byte32Reader < 'a >> for & 'a [u8 ; 32usize] { # [track_caller] fn from (value : Byte32Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a Byte32Reader < 'a >> for & 'a [u8 ; 32usize] { # [track_caller] fn from (value : & 'a Byte32Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct Uint256 (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Uint256 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Uint256 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Uint256 { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Uint256 { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Uint256 :: new_unchecked (v) } } impl Uint256 { const DEFAULT_VALUE : [u8 ; 32] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn nth4 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (4 .. 5)) } pub fn nth5 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (5 .. 6)) } pub fn nth6 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (6 .. 7)) } pub fn nth7 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (7 .. 8)) } pub fn nth8 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (8 .. 9)) } pub fn nth9 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (9 .. 10)) } pub fn nth10 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (10 .. 11)) } pub fn nth11 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (11 .. 12)) } pub fn nth12 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (12 .. 13)) } pub fn nth13 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (13 .. 14)) } pub fn nth14 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (14 .. 15)) } pub fn nth15 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (15 .. 16)) } pub fn nth16 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (16 .. 17)) } pub fn nth17 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (17 .. 18)) } pub fn nth18 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (18 .. 19)) } pub fn nth19 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (19 .. 20)) } pub fn nth20 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (20 .. 21)) } pub fn nth21 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (21 .. 22)) } pub fn nth22 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (22 .. 23)) } pub fn nth23 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (23 .. 24)) } pub fn nth24 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (24 .. 25)) } pub fn nth25 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (25 .. 26)) } pub fn nth26 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (26 .. 27)) } pub fn nth27 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (27 .. 28)) } pub fn nth28 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (28 .. 29)) } pub fn nth29 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (29 .. 30)) } pub fn nth30 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (30 .. 31)) } pub fn nth31 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (31 .. 32)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> Uint256Reader < 'r > { Uint256Reader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Uint256 { type Builder = Uint256Builder ; const NAME : & 'static str = "Uint256" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Uint256 (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint256Reader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Uint256Reader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () , self . nth4 () , self . nth5 () , self . nth6 () , self . nth7 () , self . nth8 () , self . nth9 () , self . nth10 () , self . nth11 () , self . nth12 () , self . nth13 () , self . nth14 () , self . nth15 () , self . nth16 () , self . nth17 () , self . nth18 () , self . nth19 () , self . nth20 () , self . nth21 () , self . nth22 () , self . nth23 () , self . nth24 () , self . nth25 () , self . nth26 () , self . nth27 () , self . nth28 () , self . nth29 () , self . nth30 () , self . nth31 () ,]) } } +# [derive (Clone , Copy)] pub struct Uint256Reader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Uint256Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Uint256Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Uint256Reader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > Uint256Reader < 'r > { pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn nth4 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [4 .. 5]) } pub fn nth5 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [5 .. 6]) } pub fn nth6 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [6 .. 7]) } pub fn nth7 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [7 .. 8]) } pub fn nth8 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [8 .. 9]) } pub fn nth9 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [9 .. 10]) } pub fn nth10 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [10 .. 11]) } pub fn nth11 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [11 .. 12]) } pub fn nth12 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [12 .. 13]) } pub fn nth13 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [13 .. 14]) } pub fn nth14 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [14 .. 15]) } pub fn nth15 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [15 .. 16]) } pub fn nth16 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [16 .. 17]) } pub fn nth17 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [17 .. 18]) } pub fn nth18 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [18 .. 19]) } pub fn nth19 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [19 .. 20]) } pub fn nth20 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [20 .. 21]) } pub fn nth21 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [21 .. 22]) } pub fn nth22 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [22 .. 23]) } pub fn nth23 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [23 .. 24]) } pub fn nth24 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [24 .. 25]) } pub fn nth25 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [25 .. 26]) } pub fn nth26 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [26 .. 27]) } pub fn nth27 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [27 .. 28]) } pub fn nth28 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [28 .. 29]) } pub fn nth29 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [29 .. 30]) } pub fn nth30 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [30 .. 31]) } pub fn nth31 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [31 .. 32]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for Uint256Reader < 'r > { type Entity = Uint256 ; const NAME : & 'static str = "Uint256Reader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Uint256Reader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct Uint256Builder (pub (crate) [Byte ; 32]) ; impl :: core :: fmt :: Debug for Uint256Builder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for Uint256Builder { fn default () -> Self { Uint256Builder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl Uint256Builder { pub const TOTAL_SIZE : usize = 32 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 32 ; pub fn set (mut self , v : [Byte ; 32]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } pub fn nth4 (mut self , v : Byte) -> Self { self . 0 [4] = v ; self } pub fn nth5 (mut self , v : Byte) -> Self { self . 0 [5] = v ; self } pub fn nth6 (mut self , v : Byte) -> Self { self . 0 [6] = v ; self } pub fn nth7 (mut self , v : Byte) -> Self { self . 0 [7] = v ; self } pub fn nth8 (mut self , v : Byte) -> Self { self . 0 [8] = v ; self } pub fn nth9 (mut self , v : Byte) -> Self { self . 0 [9] = v ; self } pub fn nth10 (mut self , v : Byte) -> Self { self . 0 [10] = v ; self } pub fn nth11 (mut self , v : Byte) -> Self { self . 0 [11] = v ; self } pub fn nth12 (mut self , v : Byte) -> Self { self . 0 [12] = v ; self } pub fn nth13 (mut self , v : Byte) -> Self { self . 0 [13] = v ; self } pub fn nth14 (mut self , v : Byte) -> Self { self . 0 [14] = v ; self } pub fn nth15 (mut self , v : Byte) -> Self { self . 0 [15] = v ; self } pub fn nth16 (mut self , v : Byte) -> Self { self . 0 [16] = v ; self } pub fn nth17 (mut self , v : Byte) -> Self { self . 0 [17] = v ; self } pub fn nth18 (mut self , v : Byte) -> Self { self . 0 [18] = v ; self } pub fn nth19 (mut self , v : Byte) -> Self { self . 0 [19] = v ; self } pub fn nth20 (mut self , v : Byte) -> Self { self . 0 [20] = v ; self } pub fn nth21 (mut self , v : Byte) -> Self { self . 0 [21] = v ; self } pub fn nth22 (mut self , v : Byte) -> Self { self . 0 [22] = v ; self } pub fn nth23 (mut self , v : Byte) -> Self { self . 0 [23] = v ; self } pub fn nth24 (mut self , v : Byte) -> Self { self . 0 [24] = v ; self } pub fn nth25 (mut self , v : Byte) -> Self { self . 0 [25] = v ; self } pub fn nth26 (mut self , v : Byte) -> Self { self . 0 [26] = v ; self } pub fn nth27 (mut self , v : Byte) -> Self { self . 0 [27] = v ; self } pub fn nth28 (mut self , v : Byte) -> Self { self . 0 [28] = v ; self } pub fn nth29 (mut self , v : Byte) -> Self { self . 0 [29] = v ; self } pub fn nth30 (mut self , v : Byte) -> Self { self . 0 [30] = v ; self } pub fn nth31 (mut self , v : Byte) -> Self { self . 0 [31] = v ; self } } impl molecule :: prelude :: Builder for Uint256Builder { type Entity = Uint256 ; const NAME : & 'static str = "Uint256Builder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; writer . write_all (self . 0 [4] . as_slice ()) ? ; writer . write_all (self . 0 [5] . as_slice ()) ? ; writer . write_all (self . 0 [6] . as_slice ()) ? ; writer . write_all (self . 0 [7] . as_slice ()) ? ; writer . write_all (self . 0 [8] . as_slice ()) ? ; writer . write_all (self . 0 [9] . as_slice ()) ? ; writer . write_all (self . 0 [10] . as_slice ()) ? ; writer . write_all (self . 0 [11] . as_slice ()) ? ; writer . write_all (self . 0 [12] . as_slice ()) ? ; writer . write_all (self . 0 [13] . as_slice ()) ? ; writer . write_all (self . 0 [14] . as_slice ()) ? ; writer . write_all (self . 0 [15] . as_slice ()) ? ; writer . write_all (self . 0 [16] . as_slice ()) ? ; writer . write_all (self . 0 [17] . as_slice ()) ? ; writer . write_all (self . 0 [18] . as_slice ()) ? ; writer . write_all (self . 0 [19] . as_slice ()) ? ; writer . write_all (self . 0 [20] . as_slice ()) ? ; writer . write_all (self . 0 [21] . as_slice ()) ? ; writer . write_all (self . 0 [22] . as_slice ()) ? ; writer . write_all (self . 0 [23] . as_slice ()) ? ; writer . write_all (self . 0 [24] . as_slice ()) ? ; writer . write_all (self . 0 [25] . as_slice ()) ? ; writer . write_all (self . 0 [26] . as_slice ()) ? ; writer . write_all (self . 0 [27] . as_slice ()) ? ; writer . write_all (self . 0 [28] . as_slice ()) ? ; writer . write_all (self . 0 [29] . as_slice ()) ? ; writer . write_all (self . 0 [30] . as_slice ()) ? ; writer . write_all (self . 0 [31] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Uint256 :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 32usize] > for Uint256 { fn from (value : [Byte ; 32usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for Uint256 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 32usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < Uint256 > for [Byte ; 32usize] { # [track_caller] fn from (value : Uint256) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () , value . nth4 () , value . nth5 () , value . nth6 () , value . nth7 () , value . nth8 () , value . nth9 () , value . nth10 () , value . nth11 () , value . nth12 () , value . nth13 () , value . nth14 () , value . nth15 () , value . nth16 () , value . nth17 () , value . nth18 () , value . nth19 () , value . nth20 () , value . nth21 () , value . nth22 () , value . nth23 () , value . nth24 () , value . nth25 () , value . nth26 () , value . nth27 () , value . nth28 () , value . nth29 () , value . nth30 () , value . nth31 () ,] } } impl From < [u8 ; 32usize] > for Uint256 { fn from (value : [u8 ; 32usize]) -> Self { Uint256Reader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for Uint256 { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 32usize] > :: try_from (value) ? . into ()) } } impl From < Uint256 > for [u8 ; 32usize] { # [track_caller] fn from (value : Uint256) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < Uint256Reader < 'a >> for & 'a [u8 ; 32usize] { # [track_caller] fn from (value : Uint256Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a Uint256Reader < 'a >> for & 'a [u8 ; 32usize] { # [track_caller] fn from (value : & 'a Uint256Reader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct Bytes (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Bytes { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Bytes { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Bytes { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for Bytes { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Bytes :: new_unchecked (v) } } impl Bytes { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const ITEM_SIZE : usize = 1 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < Byte > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> Byte { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; Byte :: new_unchecked (self . 0 . slice (start .. end)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . 0 . slice (molecule :: NUMBER_SIZE ..) } pub fn as_reader < 'r > (& 'r self) -> BytesReader < 'r > { BytesReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Bytes { type Builder = BytesBuilder ; const NAME : & 'static str = "Bytes" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Bytes (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct BytesReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for BytesReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for BytesReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for BytesReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > BytesReader < 'r > { pub const ITEM_SIZE : usize = 1 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < ByteReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> ByteReader < 'r > { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; ByteReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn raw_data (& self) -> & 'r [u8] { & self . as_slice () [molecule :: NUMBER_SIZE ..] } } impl < 'r > molecule :: prelude :: Reader < 'r > for BytesReader < 'r > { type Entity = Bytes ; const NAME : & 'static str = "BytesReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { BytesReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let item_count = molecule :: unpack_number (slice) as usize ; if item_count == 0 { if slice_len != molecule :: NUMBER_SIZE { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE , slice_len) ; } return Ok (()) ; } let total_size = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * item_count ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct BytesBuilder (pub (crate) Vec < Byte >) ; impl BytesBuilder { pub const ITEM_SIZE : usize = 1 ; pub fn set (mut self , v : Vec < Byte >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : Byte) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = Byte >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : Byte) -> Option < Byte > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for BytesBuilder { type Entity = Bytes ; const NAME : & 'static str = "BytesBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . 0 . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (& molecule :: pack_number (self . 0 . len () as molecule :: Number)) ? ; for inner in & self . 0 [..] { writer . write_all (inner . as_slice ()) ? ; } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Bytes :: new_unchecked (inner . into ()) } } +pub struct BytesIterator (Bytes , usize , usize) ; impl :: core :: iter :: Iterator for BytesIterator { type Item = Byte ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for BytesIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for Bytes { type Item = Byte ; type IntoIter = BytesIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; BytesIterator (self , 0 , len) } } +impl :: core :: iter :: FromIterator < Byte > for Bytes { fn from_iter < T : IntoIterator < Item = Byte >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } impl :: core :: iter :: FromIterator < u8 > for Bytes { fn from_iter < T : IntoIterator < Item = u8 >> (iter : T) -> Self { Self :: new_builder () . extend (iter . into_iter () . map (Into :: into)) . build () } } +# [derive (Clone)] pub struct BytesOpt (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for BytesOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for BytesOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for BytesOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { if let Some (v) = self . to_opt () { write ! (f , "{}(Some({}))" , Self :: NAME , v) } else { write ! (f , "{}(None)" , Self :: NAME) } } } impl :: core :: default :: Default for BytesOpt { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; BytesOpt :: new_unchecked (v) } } impl BytesOpt { const DEFAULT_VALUE : [u8 ; 0] = [] ; pub fn is_none (& self) -> bool { self . 0 . is_empty () } pub fn is_some (& self) -> bool { ! self . 0 . is_empty () } pub fn to_opt (& self) -> Option < Bytes > { if self . is_none () { None } else { Some (Bytes :: new_unchecked (self . 0 . clone ())) } } pub fn as_reader < 'r > (& 'r self) -> BytesOptReader < 'r > { BytesOptReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for BytesOpt { type Builder = BytesOptBuilder ; const NAME : & 'static str = "BytesOpt" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { BytesOpt (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesOptReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesOptReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set (self . to_opt ()) } } +# [derive (Clone , Copy)] pub struct BytesOptReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for BytesOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for BytesOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for BytesOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { if let Some (v) = self . to_opt () { write ! (f , "{}(Some({}))" , Self :: NAME , v) } else { write ! (f , "{}(None)" , Self :: NAME) } } } impl < 'r > BytesOptReader < 'r > { pub fn is_none (& self) -> bool { self . 0 . is_empty () } pub fn is_some (& self) -> bool { ! self . 0 . is_empty () } pub fn to_opt (& self) -> Option < BytesReader < 'r > > { if self . is_none () { None } else { Some (BytesReader :: new_unchecked (self . as_slice ())) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for BytesOptReader < 'r > { type Entity = BytesOpt ; const NAME : & 'static str = "BytesOptReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { BytesOptReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { if ! slice . is_empty () { BytesReader :: verify (& slice [..] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct BytesOptBuilder (pub (crate) Option < Bytes >) ; impl BytesOptBuilder { pub fn set (mut self , v : Option < Bytes >) -> Self { self . 0 = v ; self } } impl molecule :: prelude :: Builder for BytesOptBuilder { type Entity = BytesOpt ; const NAME : & 'static str = "BytesOptBuilder" ; fn expected_length (& self) -> usize { self . 0 . as_ref () . map (| ref inner | inner . as_slice () . len ()) . unwrap_or (0) } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { self . 0 . as_ref () . map (| ref inner | writer . write_all (inner . as_slice ())) . unwrap_or (Ok (())) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; BytesOpt :: new_unchecked (inner . into ()) } } +impl From < Bytes > for BytesOpt { fn from (value : Bytes) -> Self { Self :: new_builder () . set (Some (value)) . build () } } +# [derive (Clone)] pub struct BytesVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for BytesVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for BytesVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for BytesVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for BytesVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; BytesVec :: new_unchecked (v) } } impl BytesVec { const DEFAULT_VALUE : [u8 ; 4] = [4 , 0 , 0 , 0 ,] ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < Bytes > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> Bytes { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { Bytes :: new_unchecked (self . 0 . slice (start ..)) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; Bytes :: new_unchecked (self . 0 . slice (start .. end)) } } pub fn as_reader < 'r > (& 'r self) -> BytesVecReader < 'r > { BytesVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for BytesVec { type Builder = BytesVecBuilder ; const NAME : & 'static str = "BytesVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { BytesVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BytesVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct BytesVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for BytesVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for BytesVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for BytesVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > BytesVecReader < 'r > { pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < BytesReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> BytesReader < 'r > { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { BytesReader :: new_unchecked (& self . as_slice () [start ..]) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; BytesReader :: new_unchecked (& self . as_slice () [start .. end]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for BytesVecReader < 'r > { type Entity = BytesVec ; const NAME : & 'static str = "BytesVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { BytesVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len == molecule :: NUMBER_SIZE { return Ok (()) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } for pair in offsets . windows (2) { let start = pair [0] ; let end = pair [1] ; BytesReader :: verify (& slice [start .. end] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct BytesVecBuilder (pub (crate) Vec < Bytes >) ; impl BytesVecBuilder { pub fn set (mut self , v : Vec < Bytes >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : Bytes) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = Bytes >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : Bytes) -> Option < Bytes > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for BytesVecBuilder { type Entity = BytesVec ; const NAME : & 'static str = "BytesVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (self . 0 . len () + 1) + self . 0 . iter () . map (| inner | inner . as_slice () . len ()) . sum :: < usize > () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let item_count = self . 0 . len () ; if item_count == 0 { writer . write_all (& molecule :: pack_number (molecule :: NUMBER_SIZE as molecule :: Number ,)) ? ; } else { let (total_size , offsets) = self . 0 . iter () . fold ((molecule :: NUMBER_SIZE * (item_count + 1) , Vec :: with_capacity (item_count) ,) , | (start , mut offsets) , inner | { offsets . push (start) ; (start + inner . as_slice () . len () , offsets) } ,) ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } for inner in self . 0 . iter () { writer . write_all (inner . as_slice ()) ? ; } } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; BytesVec :: new_unchecked (inner . into ()) } } +pub struct BytesVecIterator (BytesVec , usize , usize) ; impl :: core :: iter :: Iterator for BytesVecIterator { type Item = Bytes ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for BytesVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for BytesVec { type Item = Bytes ; type IntoIter = BytesVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; BytesVecIterator (self , 0 , len) } } impl < 'r > BytesVecReader < 'r > { pub fn iter < 't > (& 't self) -> BytesVecReaderIterator < 't , 'r > { BytesVecReaderIterator (& self , 0 , self . len ()) } } pub struct BytesVecReaderIterator < 't , 'r > (& 't BytesVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for BytesVecReaderIterator < 't , 'r > { type Item = BytesReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for BytesVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < Bytes > for BytesVec { fn from_iter < T : IntoIterator < Item = Bytes >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct Byte32Vec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Byte32Vec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Byte32Vec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Byte32Vec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for Byte32Vec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Byte32Vec :: new_unchecked (v) } } impl Byte32Vec { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const ITEM_SIZE : usize = 32 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < Byte32 > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> Byte32 { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; Byte32 :: new_unchecked (self . 0 . slice (start .. end)) } pub fn as_reader < 'r > (& 'r self) -> Byte32VecReader < 'r > { Byte32VecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Byte32Vec { type Builder = Byte32VecBuilder ; const NAME : & 'static str = "Byte32Vec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Byte32Vec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Byte32VecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { Byte32VecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct Byte32VecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for Byte32VecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for Byte32VecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for Byte32VecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > Byte32VecReader < 'r > { pub const ITEM_SIZE : usize = 32 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < Byte32Reader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> Byte32Reader < 'r > { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; Byte32Reader :: new_unchecked (& self . as_slice () [start .. end]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for Byte32VecReader < 'r > { type Entity = Byte32Vec ; const NAME : & 'static str = "Byte32VecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { Byte32VecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let item_count = molecule :: unpack_number (slice) as usize ; if item_count == 0 { if slice_len != molecule :: NUMBER_SIZE { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE , slice_len) ; } return Ok (()) ; } let total_size = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * item_count ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct Byte32VecBuilder (pub (crate) Vec < Byte32 >) ; impl Byte32VecBuilder { pub const ITEM_SIZE : usize = 32 ; pub fn set (mut self , v : Vec < Byte32 >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : Byte32) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = Byte32 >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : Byte32) -> Option < Byte32 > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for Byte32VecBuilder { type Entity = Byte32Vec ; const NAME : & 'static str = "Byte32VecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . 0 . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (& molecule :: pack_number (self . 0 . len () as molecule :: Number)) ? ; for inner in & self . 0 [..] { writer . write_all (inner . as_slice ()) ? ; } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Byte32Vec :: new_unchecked (inner . into ()) } } +pub struct Byte32VecIterator (Byte32Vec , usize , usize) ; impl :: core :: iter :: Iterator for Byte32VecIterator { type Item = Byte32 ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for Byte32VecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for Byte32Vec { type Item = Byte32 ; type IntoIter = Byte32VecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; Byte32VecIterator (self , 0 , len) } } impl < 'r > Byte32VecReader < 'r > { pub fn iter < 't > (& 't self) -> Byte32VecReaderIterator < 't , 'r > { Byte32VecReaderIterator (& self , 0 , self . len ()) } } pub struct Byte32VecReaderIterator < 't , 'r > (& 't Byte32VecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for Byte32VecReaderIterator < 't , 'r > { type Item = Byte32Reader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for Byte32VecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < Byte32 > for Byte32Vec { fn from_iter < T : IntoIterator < Item = Byte32 >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct ScriptOpt (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for ScriptOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for ScriptOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for ScriptOpt { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { if let Some (v) = self . to_opt () { write ! (f , "{}(Some({}))" , Self :: NAME , v) } else { write ! (f , "{}(None)" , Self :: NAME) } } } impl :: core :: default :: Default for ScriptOpt { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; ScriptOpt :: new_unchecked (v) } } impl ScriptOpt { const DEFAULT_VALUE : [u8 ; 0] = [] ; pub fn is_none (& self) -> bool { self . 0 . is_empty () } pub fn is_some (& self) -> bool { ! self . 0 . is_empty () } pub fn to_opt (& self) -> Option < Script > { if self . is_none () { None } else { Some (Script :: new_unchecked (self . 0 . clone ())) } } pub fn as_reader < 'r > (& 'r self) -> ScriptOptReader < 'r > { ScriptOptReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for ScriptOpt { type Builder = ScriptOptBuilder ; const NAME : & 'static str = "ScriptOpt" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { ScriptOpt (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ScriptOptReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ScriptOptReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set (self . to_opt ()) } } +# [derive (Clone , Copy)] pub struct ScriptOptReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for ScriptOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for ScriptOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for ScriptOptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { if let Some (v) = self . to_opt () { write ! (f , "{}(Some({}))" , Self :: NAME , v) } else { write ! (f , "{}(None)" , Self :: NAME) } } } impl < 'r > ScriptOptReader < 'r > { pub fn is_none (& self) -> bool { self . 0 . is_empty () } pub fn is_some (& self) -> bool { ! self . 0 . is_empty () } pub fn to_opt (& self) -> Option < ScriptReader < 'r > > { if self . is_none () { None } else { Some (ScriptReader :: new_unchecked (self . as_slice ())) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for ScriptOptReader < 'r > { type Entity = ScriptOpt ; const NAME : & 'static str = "ScriptOptReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { ScriptOptReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { if ! slice . is_empty () { ScriptReader :: verify (& slice [..] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct ScriptOptBuilder (pub (crate) Option < Script >) ; impl ScriptOptBuilder { pub fn set (mut self , v : Option < Script >) -> Self { self . 0 = v ; self } } impl molecule :: prelude :: Builder for ScriptOptBuilder { type Entity = ScriptOpt ; const NAME : & 'static str = "ScriptOptBuilder" ; fn expected_length (& self) -> usize { self . 0 . as_ref () . map (| ref inner | inner . as_slice () . len ()) . unwrap_or (0) } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { self . 0 . as_ref () . map (| ref inner | writer . write_all (inner . as_slice ())) . unwrap_or (Ok (())) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; ScriptOpt :: new_unchecked (inner . into ()) } } +impl From < Script > for ScriptOpt { fn from (value : Script) -> Self { Self :: new_builder () . set (Some (value)) . build () } } +# [derive (Clone)] pub struct ProposalShortId (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for ProposalShortId { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for ProposalShortId { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for ProposalShortId { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl :: core :: default :: Default for ProposalShortId { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; ProposalShortId :: new_unchecked (v) } } impl ProposalShortId { const DEFAULT_VALUE : [u8 ; 10] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 10 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 10 ; pub fn nth0 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (0 .. 1)) } pub fn nth1 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (1 .. 2)) } pub fn nth2 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (2 .. 3)) } pub fn nth3 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (3 .. 4)) } pub fn nth4 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (4 .. 5)) } pub fn nth5 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (5 .. 6)) } pub fn nth6 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (6 .. 7)) } pub fn nth7 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (7 .. 8)) } pub fn nth8 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (8 .. 9)) } pub fn nth9 (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (9 .. 10)) } pub fn raw_data (& self) -> molecule :: bytes :: Bytes { self . as_bytes () } pub fn as_reader < 'r > (& 'r self) -> ProposalShortIdReader < 'r > { ProposalShortIdReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for ProposalShortId { type Builder = ProposalShortIdBuilder ; const NAME : & 'static str = "ProposalShortId" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { ProposalShortId (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ProposalShortIdReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ProposalShortIdReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . set ([self . nth0 () , self . nth1 () , self . nth2 () , self . nth3 () , self . nth4 () , self . nth5 () , self . nth6 () , self . nth7 () , self . nth8 () , self . nth9 () ,]) } } +# [derive (Clone , Copy)] pub struct ProposalShortIdReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for ProposalShortIdReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for ProposalShortIdReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for ProposalShortIdReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; let raw_data = hex_string (& self . raw_data ()) ; write ! (f , "{}(0x{})" , Self :: NAME , raw_data) } } impl < 'r > ProposalShortIdReader < 'r > { pub const TOTAL_SIZE : usize = 10 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 10 ; pub fn nth0 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [0 .. 1]) } pub fn nth1 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [1 .. 2]) } pub fn nth2 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [2 .. 3]) } pub fn nth3 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [3 .. 4]) } pub fn nth4 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [4 .. 5]) } pub fn nth5 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [5 .. 6]) } pub fn nth6 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [6 .. 7]) } pub fn nth7 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [7 .. 8]) } pub fn nth8 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [8 .. 9]) } pub fn nth9 (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [9 .. 10]) } pub fn raw_data (& self) -> & 'r [u8] { self . as_slice () } } impl < 'r > molecule :: prelude :: Reader < 'r > for ProposalShortIdReader < 'r > { type Entity = ProposalShortId ; const NAME : & 'static str = "ProposalShortIdReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { ProposalShortIdReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone)] pub struct ProposalShortIdBuilder (pub (crate) [Byte ; 10]) ; impl :: core :: fmt :: Debug for ProposalShortIdBuilder { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:?})" , Self :: NAME , & self . 0 [..]) } } impl :: core :: default :: Default for ProposalShortIdBuilder { fn default () -> Self { ProposalShortIdBuilder ([Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () , Byte :: default () ,]) } } impl ProposalShortIdBuilder { pub const TOTAL_SIZE : usize = 10 ; pub const ITEM_SIZE : usize = 1 ; pub const ITEM_COUNT : usize = 10 ; pub fn set (mut self , v : [Byte ; 10]) -> Self { self . 0 = v ; self } pub fn nth0 (mut self , v : Byte) -> Self { self . 0 [0] = v ; self } pub fn nth1 (mut self , v : Byte) -> Self { self . 0 [1] = v ; self } pub fn nth2 (mut self , v : Byte) -> Self { self . 0 [2] = v ; self } pub fn nth3 (mut self , v : Byte) -> Self { self . 0 [3] = v ; self } pub fn nth4 (mut self , v : Byte) -> Self { self . 0 [4] = v ; self } pub fn nth5 (mut self , v : Byte) -> Self { self . 0 [5] = v ; self } pub fn nth6 (mut self , v : Byte) -> Self { self . 0 [6] = v ; self } pub fn nth7 (mut self , v : Byte) -> Self { self . 0 [7] = v ; self } pub fn nth8 (mut self , v : Byte) -> Self { self . 0 [8] = v ; self } pub fn nth9 (mut self , v : Byte) -> Self { self . 0 [9] = v ; self } } impl molecule :: prelude :: Builder for ProposalShortIdBuilder { type Entity = ProposalShortId ; const NAME : & 'static str = "ProposalShortIdBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . 0 [0] . as_slice ()) ? ; writer . write_all (self . 0 [1] . as_slice ()) ? ; writer . write_all (self . 0 [2] . as_slice ()) ? ; writer . write_all (self . 0 [3] . as_slice ()) ? ; writer . write_all (self . 0 [4] . as_slice ()) ? ; writer . write_all (self . 0 [5] . as_slice ()) ? ; writer . write_all (self . 0 [6] . as_slice ()) ? ; writer . write_all (self . 0 [7] . as_slice ()) ? ; writer . write_all (self . 0 [8] . as_slice ()) ? ; writer . write_all (self . 0 [9] . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; ProposalShortId :: new_unchecked (inner . into ()) } } +impl From < [Byte ; 10usize] > for ProposalShortId { fn from (value : [Byte ; 10usize]) -> Self { Self :: new_builder () . set (value) . build () } } impl :: core :: convert :: TryFrom < & [Byte] > for ProposalShortId { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [Byte]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (Self :: new_builder () . set (< & [Byte ; 10usize] > :: try_from (value) ? . clone ()) . build ()) } } impl From < ProposalShortId > for [Byte ; 10usize] { # [track_caller] fn from (value : ProposalShortId) -> Self { [value . nth0 () , value . nth1 () , value . nth2 () , value . nth3 () , value . nth4 () , value . nth5 () , value . nth6 () , value . nth7 () , value . nth8 () , value . nth9 () ,] } } impl From < [u8 ; 10usize] > for ProposalShortId { fn from (value : [u8 ; 10usize]) -> Self { ProposalShortIdReader :: new_unchecked (& value) . to_entity () } } impl :: core :: convert :: TryFrom < & [u8] > for ProposalShortId { type Error = :: core :: array :: TryFromSliceError ; fn try_from (value : & [u8]) -> Result < Self , :: core :: array :: TryFromSliceError > { Ok (< [u8 ; 10usize] > :: try_from (value) ? . into ()) } } impl From < ProposalShortId > for [u8 ; 10usize] { # [track_caller] fn from (value : ProposalShortId) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < ProposalShortIdReader < 'a >> for & 'a [u8 ; 10usize] { # [track_caller] fn from (value : ProposalShortIdReader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } impl < 'a > From < & 'a ProposalShortIdReader < 'a >> for & 'a [u8 ; 10usize] { # [track_caller] fn from (value : & 'a ProposalShortIdReader < 'a >) -> Self { :: core :: convert :: TryFrom :: try_from (value . as_slice ()) . unwrap () } } +# [derive (Clone)] pub struct UncleBlockVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for UncleBlockVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for UncleBlockVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for UncleBlockVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for UncleBlockVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; UncleBlockVec :: new_unchecked (v) } } impl UncleBlockVec { const DEFAULT_VALUE : [u8 ; 4] = [4 , 0 , 0 , 0 ,] ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < UncleBlock > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> UncleBlock { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { UncleBlock :: new_unchecked (self . 0 . slice (start ..)) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; UncleBlock :: new_unchecked (self . 0 . slice (start .. end)) } } pub fn as_reader < 'r > (& 'r self) -> UncleBlockVecReader < 'r > { UncleBlockVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for UncleBlockVec { type Builder = UncleBlockVecBuilder ; const NAME : & 'static str = "UncleBlockVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { UncleBlockVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { UncleBlockVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { UncleBlockVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct UncleBlockVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for UncleBlockVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for UncleBlockVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for UncleBlockVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > UncleBlockVecReader < 'r > { pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < UncleBlockReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> UncleBlockReader < 'r > { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { UncleBlockReader :: new_unchecked (& self . as_slice () [start ..]) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; UncleBlockReader :: new_unchecked (& self . as_slice () [start .. end]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for UncleBlockVecReader < 'r > { type Entity = UncleBlockVec ; const NAME : & 'static str = "UncleBlockVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { UncleBlockVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len == molecule :: NUMBER_SIZE { return Ok (()) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } for pair in offsets . windows (2) { let start = pair [0] ; let end = pair [1] ; UncleBlockReader :: verify (& slice [start .. end] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct UncleBlockVecBuilder (pub (crate) Vec < UncleBlock >) ; impl UncleBlockVecBuilder { pub fn set (mut self , v : Vec < UncleBlock >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : UncleBlock) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = UncleBlock >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : UncleBlock) -> Option < UncleBlock > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for UncleBlockVecBuilder { type Entity = UncleBlockVec ; const NAME : & 'static str = "UncleBlockVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (self . 0 . len () + 1) + self . 0 . iter () . map (| inner | inner . as_slice () . len ()) . sum :: < usize > () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let item_count = self . 0 . len () ; if item_count == 0 { writer . write_all (& molecule :: pack_number (molecule :: NUMBER_SIZE as molecule :: Number ,)) ? ; } else { let (total_size , offsets) = self . 0 . iter () . fold ((molecule :: NUMBER_SIZE * (item_count + 1) , Vec :: with_capacity (item_count) ,) , | (start , mut offsets) , inner | { offsets . push (start) ; (start + inner . as_slice () . len () , offsets) } ,) ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } for inner in self . 0 . iter () { writer . write_all (inner . as_slice ()) ? ; } } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; UncleBlockVec :: new_unchecked (inner . into ()) } } +pub struct UncleBlockVecIterator (UncleBlockVec , usize , usize) ; impl :: core :: iter :: Iterator for UncleBlockVecIterator { type Item = UncleBlock ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for UncleBlockVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for UncleBlockVec { type Item = UncleBlock ; type IntoIter = UncleBlockVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; UncleBlockVecIterator (self , 0 , len) } } impl < 'r > UncleBlockVecReader < 'r > { pub fn iter < 't > (& 't self) -> UncleBlockVecReaderIterator < 't , 'r > { UncleBlockVecReaderIterator (& self , 0 , self . len ()) } } pub struct UncleBlockVecReaderIterator < 't , 'r > (& 't UncleBlockVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for UncleBlockVecReaderIterator < 't , 'r > { type Item = UncleBlockReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for UncleBlockVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < UncleBlock > for UncleBlockVec { fn from_iter < T : IntoIterator < Item = UncleBlock >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct TransactionVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for TransactionVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for TransactionVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for TransactionVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for TransactionVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; TransactionVec :: new_unchecked (v) } } impl TransactionVec { const DEFAULT_VALUE : [u8 ; 4] = [4 , 0 , 0 , 0 ,] ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < Transaction > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> Transaction { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { Transaction :: new_unchecked (self . 0 . slice (start ..)) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; Transaction :: new_unchecked (self . 0 . slice (start .. end)) } } pub fn as_reader < 'r > (& 'r self) -> TransactionVecReader < 'r > { TransactionVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for TransactionVec { type Builder = TransactionVecBuilder ; const NAME : & 'static str = "TransactionVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { TransactionVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { TransactionVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { TransactionVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct TransactionVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for TransactionVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for TransactionVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for TransactionVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > TransactionVecReader < 'r > { pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < TransactionReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> TransactionReader < 'r > { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { TransactionReader :: new_unchecked (& self . as_slice () [start ..]) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; TransactionReader :: new_unchecked (& self . as_slice () [start .. end]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for TransactionVecReader < 'r > { type Entity = TransactionVec ; const NAME : & 'static str = "TransactionVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { TransactionVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len == molecule :: NUMBER_SIZE { return Ok (()) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } for pair in offsets . windows (2) { let start = pair [0] ; let end = pair [1] ; TransactionReader :: verify (& slice [start .. end] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct TransactionVecBuilder (pub (crate) Vec < Transaction >) ; impl TransactionVecBuilder { pub fn set (mut self , v : Vec < Transaction >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : Transaction) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = Transaction >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : Transaction) -> Option < Transaction > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for TransactionVecBuilder { type Entity = TransactionVec ; const NAME : & 'static str = "TransactionVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (self . 0 . len () + 1) + self . 0 . iter () . map (| inner | inner . as_slice () . len ()) . sum :: < usize > () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let item_count = self . 0 . len () ; if item_count == 0 { writer . write_all (& molecule :: pack_number (molecule :: NUMBER_SIZE as molecule :: Number ,)) ? ; } else { let (total_size , offsets) = self . 0 . iter () . fold ((molecule :: NUMBER_SIZE * (item_count + 1) , Vec :: with_capacity (item_count) ,) , | (start , mut offsets) , inner | { offsets . push (start) ; (start + inner . as_slice () . len () , offsets) } ,) ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } for inner in self . 0 . iter () { writer . write_all (inner . as_slice ()) ? ; } } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; TransactionVec :: new_unchecked (inner . into ()) } } +pub struct TransactionVecIterator (TransactionVec , usize , usize) ; impl :: core :: iter :: Iterator for TransactionVecIterator { type Item = Transaction ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for TransactionVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for TransactionVec { type Item = Transaction ; type IntoIter = TransactionVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; TransactionVecIterator (self , 0 , len) } } impl < 'r > TransactionVecReader < 'r > { pub fn iter < 't > (& 't self) -> TransactionVecReaderIterator < 't , 'r > { TransactionVecReaderIterator (& self , 0 , self . len ()) } } pub struct TransactionVecReaderIterator < 't , 'r > (& 't TransactionVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for TransactionVecReaderIterator < 't , 'r > { type Item = TransactionReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for TransactionVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < Transaction > for TransactionVec { fn from_iter < T : IntoIterator < Item = Transaction >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct ProposalShortIdVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for ProposalShortIdVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for ProposalShortIdVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for ProposalShortIdVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for ProposalShortIdVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; ProposalShortIdVec :: new_unchecked (v) } } impl ProposalShortIdVec { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const ITEM_SIZE : usize = 10 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < ProposalShortId > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> ProposalShortId { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; ProposalShortId :: new_unchecked (self . 0 . slice (start .. end)) } pub fn as_reader < 'r > (& 'r self) -> ProposalShortIdVecReader < 'r > { ProposalShortIdVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for ProposalShortIdVec { type Builder = ProposalShortIdVecBuilder ; const NAME : & 'static str = "ProposalShortIdVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { ProposalShortIdVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ProposalShortIdVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ProposalShortIdVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct ProposalShortIdVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for ProposalShortIdVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for ProposalShortIdVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for ProposalShortIdVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > ProposalShortIdVecReader < 'r > { pub const ITEM_SIZE : usize = 10 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < ProposalShortIdReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> ProposalShortIdReader < 'r > { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; ProposalShortIdReader :: new_unchecked (& self . as_slice () [start .. end]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for ProposalShortIdVecReader < 'r > { type Entity = ProposalShortIdVec ; const NAME : & 'static str = "ProposalShortIdVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { ProposalShortIdVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let item_count = molecule :: unpack_number (slice) as usize ; if item_count == 0 { if slice_len != molecule :: NUMBER_SIZE { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE , slice_len) ; } return Ok (()) ; } let total_size = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * item_count ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct ProposalShortIdVecBuilder (pub (crate) Vec < ProposalShortId >) ; impl ProposalShortIdVecBuilder { pub const ITEM_SIZE : usize = 10 ; pub fn set (mut self , v : Vec < ProposalShortId >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : ProposalShortId) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = ProposalShortId >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : ProposalShortId) -> Option < ProposalShortId > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for ProposalShortIdVecBuilder { type Entity = ProposalShortIdVec ; const NAME : & 'static str = "ProposalShortIdVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . 0 . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (& molecule :: pack_number (self . 0 . len () as molecule :: Number)) ? ; for inner in & self . 0 [..] { writer . write_all (inner . as_slice ()) ? ; } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; ProposalShortIdVec :: new_unchecked (inner . into ()) } } +pub struct ProposalShortIdVecIterator (ProposalShortIdVec , usize , usize) ; impl :: core :: iter :: Iterator for ProposalShortIdVecIterator { type Item = ProposalShortId ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for ProposalShortIdVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for ProposalShortIdVec { type Item = ProposalShortId ; type IntoIter = ProposalShortIdVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; ProposalShortIdVecIterator (self , 0 , len) } } impl < 'r > ProposalShortIdVecReader < 'r > { pub fn iter < 't > (& 't self) -> ProposalShortIdVecReaderIterator < 't , 'r > { ProposalShortIdVecReaderIterator (& self , 0 , self . len ()) } } pub struct ProposalShortIdVecReaderIterator < 't , 'r > (& 't ProposalShortIdVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for ProposalShortIdVecReaderIterator < 't , 'r > { type Item = ProposalShortIdReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for ProposalShortIdVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < ProposalShortId > for ProposalShortIdVec { fn from_iter < T : IntoIterator < Item = ProposalShortId >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct CellDepVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellDepVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellDepVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellDepVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for CellDepVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellDepVec :: new_unchecked (v) } } impl CellDepVec { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const ITEM_SIZE : usize = 37 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellDep > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellDep { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; CellDep :: new_unchecked (self . 0 . slice (start .. end)) } pub fn as_reader < 'r > (& 'r self) -> CellDepVecReader < 'r > { CellDepVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellDepVec { type Builder = CellDepVecBuilder ; const NAME : & 'static str = "CellDepVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellDepVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellDepVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellDepVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct CellDepVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellDepVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellDepVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellDepVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > CellDepVecReader < 'r > { pub const ITEM_SIZE : usize = 37 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellDepReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellDepReader < 'r > { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; CellDepReader :: new_unchecked (& self . as_slice () [start .. end]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellDepVecReader < 'r > { type Entity = CellDepVec ; const NAME : & 'static str = "CellDepVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellDepVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let item_count = molecule :: unpack_number (slice) as usize ; if item_count == 0 { if slice_len != molecule :: NUMBER_SIZE { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE , slice_len) ; } return Ok (()) ; } let total_size = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * item_count ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellDepVecBuilder (pub (crate) Vec < CellDep >) ; impl CellDepVecBuilder { pub const ITEM_SIZE : usize = 37 ; pub fn set (mut self , v : Vec < CellDep >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : CellDep) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = CellDep >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : CellDep) -> Option < CellDep > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for CellDepVecBuilder { type Entity = CellDepVec ; const NAME : & 'static str = "CellDepVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . 0 . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (& molecule :: pack_number (self . 0 . len () as molecule :: Number)) ? ; for inner in & self . 0 [..] { writer . write_all (inner . as_slice ()) ? ; } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellDepVec :: new_unchecked (inner . into ()) } } +pub struct CellDepVecIterator (CellDepVec , usize , usize) ; impl :: core :: iter :: Iterator for CellDepVecIterator { type Item = CellDep ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for CellDepVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for CellDepVec { type Item = CellDep ; type IntoIter = CellDepVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; CellDepVecIterator (self , 0 , len) } } impl < 'r > CellDepVecReader < 'r > { pub fn iter < 't > (& 't self) -> CellDepVecReaderIterator < 't , 'r > { CellDepVecReaderIterator (& self , 0 , self . len ()) } } pub struct CellDepVecReaderIterator < 't , 'r > (& 't CellDepVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for CellDepVecReaderIterator < 't , 'r > { type Item = CellDepReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for CellDepVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < CellDep > for CellDepVec { fn from_iter < T : IntoIterator < Item = CellDep >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct CellInputVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellInputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellInputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellInputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for CellInputVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellInputVec :: new_unchecked (v) } } impl CellInputVec { const DEFAULT_VALUE : [u8 ; 4] = [0 , 0 , 0 , 0 ,] ; pub const ITEM_SIZE : usize = 44 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellInput > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellInput { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; CellInput :: new_unchecked (self . 0 . slice (start .. end)) } pub fn as_reader < 'r > (& 'r self) -> CellInputVecReader < 'r > { CellInputVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellInputVec { type Builder = CellInputVecBuilder ; const NAME : & 'static str = "CellInputVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellInputVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellInputVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellInputVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct CellInputVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellInputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellInputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellInputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > CellInputVecReader < 'r > { pub const ITEM_SIZE : usize = 44 ; pub fn total_size (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . item_count () } pub fn item_count (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellInputReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellInputReader < 'r > { let start = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * idx ; let end = start + Self :: ITEM_SIZE ; CellInputReader :: new_unchecked (& self . as_slice () [start .. end]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellInputVecReader < 'r > { type Entity = CellInputVec ; const NAME : & 'static str = "CellInputVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellInputVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let item_count = molecule :: unpack_number (slice) as usize ; if item_count == 0 { if slice_len != molecule :: NUMBER_SIZE { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE , slice_len) ; } return Ok (()) ; } let total_size = molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * item_count ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellInputVecBuilder (pub (crate) Vec < CellInput >) ; impl CellInputVecBuilder { pub const ITEM_SIZE : usize = 44 ; pub fn set (mut self , v : Vec < CellInput >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : CellInput) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = CellInput >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : CellInput) -> Option < CellInput > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for CellInputVecBuilder { type Entity = CellInputVec ; const NAME : & 'static str = "CellInputVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE + Self :: ITEM_SIZE * self . 0 . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (& molecule :: pack_number (self . 0 . len () as molecule :: Number)) ? ; for inner in & self . 0 [..] { writer . write_all (inner . as_slice ()) ? ; } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellInputVec :: new_unchecked (inner . into ()) } } +pub struct CellInputVecIterator (CellInputVec , usize , usize) ; impl :: core :: iter :: Iterator for CellInputVecIterator { type Item = CellInput ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for CellInputVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for CellInputVec { type Item = CellInput ; type IntoIter = CellInputVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; CellInputVecIterator (self , 0 , len) } } impl < 'r > CellInputVecReader < 'r > { pub fn iter < 't > (& 't self) -> CellInputVecReaderIterator < 't , 'r > { CellInputVecReaderIterator (& self , 0 , self . len ()) } } pub struct CellInputVecReaderIterator < 't , 'r > (& 't CellInputVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for CellInputVecReaderIterator < 't , 'r > { type Item = CellInputReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for CellInputVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < CellInput > for CellInputVec { fn from_iter < T : IntoIterator < Item = CellInput >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct CellOutputVec (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellOutputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellOutputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellOutputVec { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl :: core :: default :: Default for CellOutputVec { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellOutputVec :: new_unchecked (v) } } impl CellOutputVec { const DEFAULT_VALUE : [u8 ; 4] = [4 , 0 , 0 , 0 ,] ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellOutput > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellOutput { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { CellOutput :: new_unchecked (self . 0 . slice (start ..)) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; CellOutput :: new_unchecked (self . 0 . slice (start .. end)) } } pub fn as_reader < 'r > (& 'r self) -> CellOutputVecReader < 'r > { CellOutputVecReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellOutputVec { type Builder = CellOutputVecBuilder ; const NAME : & 'static str = "CellOutputVec" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellOutputVec (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellOutputVecReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellOutputVecReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . extend (self . into_iter ()) } } +# [derive (Clone , Copy)] pub struct CellOutputVecReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellOutputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellOutputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellOutputVecReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} [" , Self :: NAME) ? ; for i in 0 .. self . len () { if i == 0 { write ! (f , "{}" , self . get_unchecked (i)) ? ; } else { write ! (f , ", {}" , self . get_unchecked (i)) ? ; } } write ! (f , "]") } } impl < 'r > CellOutputVecReader < 'r > { pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn item_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn len (& self) -> usize { self . item_count () } pub fn is_empty (& self) -> bool { self . len () == 0 } pub fn get (& self , idx : usize) -> Option < CellOutputReader < 'r > > { if idx >= self . len () { None } else { Some (self . get_unchecked (idx)) } } pub fn get_unchecked (& self , idx : usize) -> CellOutputReader < 'r > { let slice = self . as_slice () ; let start_idx = molecule :: NUMBER_SIZE * (1 + idx) ; let start = molecule :: unpack_number (& slice [start_idx ..]) as usize ; if idx == self . len () - 1 { CellOutputReader :: new_unchecked (& self . as_slice () [start ..]) } else { let end_idx = start_idx + molecule :: NUMBER_SIZE ; let end = molecule :: unpack_number (& slice [end_idx ..]) as usize ; CellOutputReader :: new_unchecked (& self . as_slice () [start .. end]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellOutputVecReader < 'r > { type Entity = CellOutputVec ; const NAME : & 'static str = "CellOutputVecReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellOutputVecReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len == molecule :: NUMBER_SIZE { return Ok (()) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , TotalSizeNotMatch , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } for pair in offsets . windows (2) { let start = pair [0] ; let end = pair [1] ; CellOutputReader :: verify (& slice [start .. end] , compatible) ? ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellOutputVecBuilder (pub (crate) Vec < CellOutput >) ; impl CellOutputVecBuilder { pub fn set (mut self , v : Vec < CellOutput >) -> Self { self . 0 = v ; self } pub fn push (mut self , v : CellOutput) -> Self { self . 0 . push (v) ; self } pub fn extend < T : :: core :: iter :: IntoIterator < Item = CellOutput >> (mut self , iter : T) -> Self { for elem in iter { self . 0 . push (elem) ; } self } pub fn replace (& mut self , index : usize , v : CellOutput) -> Option < CellOutput > { self . 0 . get_mut (index) . map (| item | :: core :: mem :: replace (item , v)) } } impl molecule :: prelude :: Builder for CellOutputVecBuilder { type Entity = CellOutputVec ; const NAME : & 'static str = "CellOutputVecBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (self . 0 . len () + 1) + self . 0 . iter () . map (| inner | inner . as_slice () . len ()) . sum :: < usize > () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let item_count = self . 0 . len () ; if item_count == 0 { writer . write_all (& molecule :: pack_number (molecule :: NUMBER_SIZE as molecule :: Number ,)) ? ; } else { let (total_size , offsets) = self . 0 . iter () . fold ((molecule :: NUMBER_SIZE * (item_count + 1) , Vec :: with_capacity (item_count) ,) , | (start , mut offsets) , inner | { offsets . push (start) ; (start + inner . as_slice () . len () , offsets) } ,) ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } for inner in self . 0 . iter () { writer . write_all (inner . as_slice ()) ? ; } } Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellOutputVec :: new_unchecked (inner . into ()) } } +pub struct CellOutputVecIterator (CellOutputVec , usize , usize) ; impl :: core :: iter :: Iterator for CellOutputVecIterator { type Item = CellOutput ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl :: core :: iter :: ExactSizeIterator for CellOutputVecIterator { fn len (& self) -> usize { self . 2 - self . 1 } } impl :: core :: iter :: IntoIterator for CellOutputVec { type Item = CellOutput ; type IntoIter = CellOutputVecIterator ; fn into_iter (self) -> Self :: IntoIter { let len = self . len () ; CellOutputVecIterator (self , 0 , len) } } impl < 'r > CellOutputVecReader < 'r > { pub fn iter < 't > (& 't self) -> CellOutputVecReaderIterator < 't , 'r > { CellOutputVecReaderIterator (& self , 0 , self . len ()) } } pub struct CellOutputVecReaderIterator < 't , 'r > (& 't CellOutputVecReader < 'r > , usize , usize) ; impl < 't : 'r , 'r > :: core :: iter :: Iterator for CellOutputVecReaderIterator < 't , 'r > { type Item = CellOutputReader < 't > ; fn next (& mut self) -> Option < Self :: Item > { if self . 1 >= self . 2 { None } else { let ret = self . 0 . get_unchecked (self . 1) ; self . 1 += 1 ; Some (ret) } } } impl < 't : 'r , 'r > :: core :: iter :: ExactSizeIterator for CellOutputVecReaderIterator < 't , 'r > { fn len (& self) -> usize { self . 2 - self . 1 } } +impl :: core :: iter :: FromIterator < CellOutput > for CellOutputVec { fn from_iter < T : IntoIterator < Item = CellOutput >> (iter : T) -> Self { Self :: new_builder () . extend (iter) . build () } } +# [derive (Clone)] pub struct Script (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Script { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Script { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Script { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "code_hash" , self . code_hash ()) ? ; write ! (f , ", {}: {}" , "hash_type" , self . hash_type ()) ? ; write ! (f , ", {}: {}" , "args" , self . args ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for Script { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Script :: new_unchecked (v) } } impl Script { const DEFAULT_VALUE : [u8 ; 53] = [53 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 49 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn code_hash (& self) -> Byte32 { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Byte32 :: new_unchecked (self . 0 . slice (start .. end)) } pub fn hash_type (& self) -> Byte { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; Byte :: new_unchecked (self . 0 . slice (start .. end)) } pub fn args (& self) -> Bytes { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; Bytes :: new_unchecked (self . 0 . slice (start .. end)) } else { Bytes :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> ScriptReader < 'r > { ScriptReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Script { type Builder = ScriptBuilder ; const NAME : & 'static str = "Script" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Script (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ScriptReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { ScriptReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . code_hash (self . code_hash ()) . hash_type (self . hash_type ()) . args (self . args ()) } } +# [derive (Clone , Copy)] pub struct ScriptReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for ScriptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for ScriptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for ScriptReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "code_hash" , self . code_hash ()) ? ; write ! (f , ", {}: {}" , "hash_type" , self . hash_type ()) ? ; write ! (f , ", {}: {}" , "args" , self . args ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > ScriptReader < 'r > { pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn code_hash (& self) -> Byte32Reader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Byte32Reader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn hash_type (& self) -> ByteReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; ByteReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn args (& self) -> BytesReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; BytesReader :: new_unchecked (& self . as_slice () [start .. end]) } else { BytesReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for ScriptReader < 'r > { type Entity = Script ; const NAME : & 'static str = "ScriptReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { ScriptReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } Byte32Reader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; ByteReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; BytesReader :: verify (& slice [offsets [2] .. offsets [3]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct ScriptBuilder { pub (crate) code_hash : Byte32 , pub (crate) hash_type : Byte , pub (crate) args : Bytes , } impl ScriptBuilder { pub const FIELD_COUNT : usize = 3 ; pub fn code_hash (mut self , v : Byte32) -> Self { self . code_hash = v ; self } pub fn hash_type (mut self , v : Byte) -> Self { self . hash_type = v ; self } pub fn args (mut self , v : Bytes) -> Self { self . args = v ; self } } impl molecule :: prelude :: Builder for ScriptBuilder { type Entity = Script ; const NAME : & 'static str = "ScriptBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . code_hash . as_slice () . len () + self . hash_type . as_slice () . len () + self . args . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . code_hash . as_slice () . len () ; offsets . push (total_size) ; total_size += self . hash_type . as_slice () . len () ; offsets . push (total_size) ; total_size += self . args . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . code_hash . as_slice ()) ? ; writer . write_all (self . hash_type . as_slice ()) ? ; writer . write_all (self . args . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Script :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct OutPoint (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for OutPoint { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for OutPoint { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for OutPoint { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "tx_hash" , self . tx_hash ()) ? ; write ! (f , ", {}: {}" , "index" , self . index ()) ? ; write ! (f , " }}") } } impl :: core :: default :: Default for OutPoint { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; OutPoint :: new_unchecked (v) } } impl OutPoint { const DEFAULT_VALUE : [u8 ; 36] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 36 ; pub const FIELD_SIZES : [usize ; 2] = [32 , 4 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn tx_hash (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (0 .. 32)) } pub fn index (& self) -> Uint32 { Uint32 :: new_unchecked (self . 0 . slice (32 .. 36)) } pub fn as_reader < 'r > (& 'r self) -> OutPointReader < 'r > { OutPointReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for OutPoint { type Builder = OutPointBuilder ; const NAME : & 'static str = "OutPoint" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { OutPoint (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { OutPointReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { OutPointReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . tx_hash (self . tx_hash ()) . index (self . index ()) } } +# [derive (Clone , Copy)] pub struct OutPointReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for OutPointReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for OutPointReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for OutPointReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "tx_hash" , self . tx_hash ()) ? ; write ! (f , ", {}: {}" , "index" , self . index ()) ? ; write ! (f , " }}") } } impl < 'r > OutPointReader < 'r > { pub const TOTAL_SIZE : usize = 36 ; pub const FIELD_SIZES : [usize ; 2] = [32 , 4 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn tx_hash (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [0 .. 32]) } pub fn index (& self) -> Uint32Reader < 'r > { Uint32Reader :: new_unchecked (& self . as_slice () [32 .. 36]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for OutPointReader < 'r > { type Entity = OutPoint ; const NAME : & 'static str = "OutPointReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { OutPointReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct OutPointBuilder { pub (crate) tx_hash : Byte32 , pub (crate) index : Uint32 , } impl OutPointBuilder { pub const TOTAL_SIZE : usize = 36 ; pub const FIELD_SIZES : [usize ; 2] = [32 , 4 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn tx_hash (mut self , v : Byte32) -> Self { self . tx_hash = v ; self } pub fn index (mut self , v : Uint32) -> Self { self . index = v ; self } } impl molecule :: prelude :: Builder for OutPointBuilder { type Entity = OutPoint ; const NAME : & 'static str = "OutPointBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . tx_hash . as_slice ()) ? ; writer . write_all (self . index . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; OutPoint :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct CellInput (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellInput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellInput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellInput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "since" , self . since ()) ? ; write ! (f , ", {}: {}" , "previous_output" , self . previous_output ()) ? ; write ! (f , " }}") } } impl :: core :: default :: Default for CellInput { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellInput :: new_unchecked (v) } } impl CellInput { const DEFAULT_VALUE : [u8 ; 44] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 44 ; pub const FIELD_SIZES : [usize ; 2] = [8 , 36 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn since (& self) -> Uint64 { Uint64 :: new_unchecked (self . 0 . slice (0 .. 8)) } pub fn previous_output (& self) -> OutPoint { OutPoint :: new_unchecked (self . 0 . slice (8 .. 44)) } pub fn as_reader < 'r > (& 'r self) -> CellInputReader < 'r > { CellInputReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellInput { type Builder = CellInputBuilder ; const NAME : & 'static str = "CellInput" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellInput (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellInputReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellInputReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . since (self . since ()) . previous_output (self . previous_output ()) } } +# [derive (Clone , Copy)] pub struct CellInputReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellInputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellInputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellInputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "since" , self . since ()) ? ; write ! (f , ", {}: {}" , "previous_output" , self . previous_output ()) ? ; write ! (f , " }}") } } impl < 'r > CellInputReader < 'r > { pub const TOTAL_SIZE : usize = 44 ; pub const FIELD_SIZES : [usize ; 2] = [8 , 36 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn since (& self) -> Uint64Reader < 'r > { Uint64Reader :: new_unchecked (& self . as_slice () [0 .. 8]) } pub fn previous_output (& self) -> OutPointReader < 'r > { OutPointReader :: new_unchecked (& self . as_slice () [8 .. 44]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellInputReader < 'r > { type Entity = CellInput ; const NAME : & 'static str = "CellInputReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellInputReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellInputBuilder { pub (crate) since : Uint64 , pub (crate) previous_output : OutPoint , } impl CellInputBuilder { pub const TOTAL_SIZE : usize = 44 ; pub const FIELD_SIZES : [usize ; 2] = [8 , 36 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn since (mut self , v : Uint64) -> Self { self . since = v ; self } pub fn previous_output (mut self , v : OutPoint) -> Self { self . previous_output = v ; self } } impl molecule :: prelude :: Builder for CellInputBuilder { type Entity = CellInput ; const NAME : & 'static str = "CellInputBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . since . as_slice ()) ? ; writer . write_all (self . previous_output . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellInput :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct CellOutput (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellOutput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellOutput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellOutput { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "capacity" , self . capacity ()) ? ; write ! (f , ", {}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "type_" , self . type_ ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for CellOutput { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellOutput :: new_unchecked (v) } } impl CellOutput { const DEFAULT_VALUE : [u8 ; 77] = [77 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 24 , 0 , 0 , 0 , 77 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 53 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 49 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn capacity (& self) -> Uint64 { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Uint64 :: new_unchecked (self . 0 . slice (start .. end)) } pub fn lock (& self) -> Script { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; Script :: new_unchecked (self . 0 . slice (start .. end)) } pub fn type_ (& self) -> ScriptOpt { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; ScriptOpt :: new_unchecked (self . 0 . slice (start .. end)) } else { ScriptOpt :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> CellOutputReader < 'r > { CellOutputReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellOutput { type Builder = CellOutputBuilder ; const NAME : & 'static str = "CellOutput" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellOutput (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellOutputReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellOutputReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . capacity (self . capacity ()) . lock (self . lock ()) . type_ (self . type_ ()) } } +# [derive (Clone , Copy)] pub struct CellOutputReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellOutputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellOutputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellOutputReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "capacity" , self . capacity ()) ? ; write ! (f , ", {}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "type_" , self . type_ ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > CellOutputReader < 'r > { pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn capacity (& self) -> Uint64Reader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Uint64Reader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn lock (& self) -> ScriptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; ScriptReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn type_ (& self) -> ScriptOptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; ScriptOptReader :: new_unchecked (& self . as_slice () [start .. end]) } else { ScriptOptReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellOutputReader < 'r > { type Entity = CellOutput ; const NAME : & 'static str = "CellOutputReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellOutputReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } Uint64Reader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; ScriptReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; ScriptOptReader :: verify (& slice [offsets [2] .. offsets [3]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellOutputBuilder { pub (crate) capacity : Uint64 , pub (crate) lock : Script , pub (crate) type_ : ScriptOpt , } impl CellOutputBuilder { pub const FIELD_COUNT : usize = 3 ; pub fn capacity (mut self , v : Uint64) -> Self { self . capacity = v ; self } pub fn lock (mut self , v : Script) -> Self { self . lock = v ; self } pub fn type_ (mut self , v : ScriptOpt) -> Self { self . type_ = v ; self } } impl molecule :: prelude :: Builder for CellOutputBuilder { type Entity = CellOutput ; const NAME : & 'static str = "CellOutputBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . capacity . as_slice () . len () + self . lock . as_slice () . len () + self . type_ . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . capacity . as_slice () . len () ; offsets . push (total_size) ; total_size += self . lock . as_slice () . len () ; offsets . push (total_size) ; total_size += self . type_ . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . capacity . as_slice ()) ? ; writer . write_all (self . lock . as_slice ()) ? ; writer . write_all (self . type_ . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellOutput :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct CellDep (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellDep { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellDep { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellDep { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "out_point" , self . out_point ()) ? ; write ! (f , ", {}: {}" , "dep_type" , self . dep_type ()) ? ; write ! (f , " }}") } } impl :: core :: default :: Default for CellDep { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellDep :: new_unchecked (v) } } impl CellDep { const DEFAULT_VALUE : [u8 ; 37] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 37 ; pub const FIELD_SIZES : [usize ; 2] = [36 , 1 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn out_point (& self) -> OutPoint { OutPoint :: new_unchecked (self . 0 . slice (0 .. 36)) } pub fn dep_type (& self) -> Byte { Byte :: new_unchecked (self . 0 . slice (36 .. 37)) } pub fn as_reader < 'r > (& 'r self) -> CellDepReader < 'r > { CellDepReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellDep { type Builder = CellDepBuilder ; const NAME : & 'static str = "CellDep" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellDep (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellDepReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellDepReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . out_point (self . out_point ()) . dep_type (self . dep_type ()) } } +# [derive (Clone , Copy)] pub struct CellDepReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellDepReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellDepReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellDepReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "out_point" , self . out_point ()) ? ; write ! (f , ", {}: {}" , "dep_type" , self . dep_type ()) ? ; write ! (f , " }}") } } impl < 'r > CellDepReader < 'r > { pub const TOTAL_SIZE : usize = 37 ; pub const FIELD_SIZES : [usize ; 2] = [36 , 1 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn out_point (& self) -> OutPointReader < 'r > { OutPointReader :: new_unchecked (& self . as_slice () [0 .. 36]) } pub fn dep_type (& self) -> ByteReader < 'r > { ByteReader :: new_unchecked (& self . as_slice () [36 .. 37]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellDepReader < 'r > { type Entity = CellDep ; const NAME : & 'static str = "CellDepReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellDepReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellDepBuilder { pub (crate) out_point : OutPoint , pub (crate) dep_type : Byte , } impl CellDepBuilder { pub const TOTAL_SIZE : usize = 37 ; pub const FIELD_SIZES : [usize ; 2] = [36 , 1 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn out_point (mut self , v : OutPoint) -> Self { self . out_point = v ; self } pub fn dep_type (mut self , v : Byte) -> Self { self . dep_type = v ; self } } impl molecule :: prelude :: Builder for CellDepBuilder { type Entity = CellDep ; const NAME : & 'static str = "CellDepBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . out_point . as_slice ()) ? ; writer . write_all (self . dep_type . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellDep :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct RawTransaction (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for RawTransaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for RawTransaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for RawTransaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "version" , self . version ()) ? ; write ! (f , ", {}: {}" , "cell_deps" , self . cell_deps ()) ? ; write ! (f , ", {}: {}" , "header_deps" , self . header_deps ()) ? ; write ! (f , ", {}: {}" , "inputs" , self . inputs ()) ? ; write ! (f , ", {}: {}" , "outputs" , self . outputs ()) ? ; write ! (f , ", {}: {}" , "outputs_data" , self . outputs_data ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for RawTransaction { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; RawTransaction :: new_unchecked (v) } } impl RawTransaction { const DEFAULT_VALUE : [u8 ; 52] = [52 , 0 , 0 , 0 , 28 , 0 , 0 , 0 , 32 , 0 , 0 , 0 , 36 , 0 , 0 , 0 , 40 , 0 , 0 , 0 , 44 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 6 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn version (& self) -> Uint32 { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Uint32 :: new_unchecked (self . 0 . slice (start .. end)) } pub fn cell_deps (& self) -> CellDepVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; CellDepVec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn header_deps (& self) -> Byte32Vec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; let end = molecule :: unpack_number (& slice [16 ..]) as usize ; Byte32Vec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn inputs (& self) -> CellInputVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [16 ..]) as usize ; let end = molecule :: unpack_number (& slice [20 ..]) as usize ; CellInputVec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn outputs (& self) -> CellOutputVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [20 ..]) as usize ; let end = molecule :: unpack_number (& slice [24 ..]) as usize ; CellOutputVec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn outputs_data (& self) -> BytesVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [24 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [28 ..]) as usize ; BytesVec :: new_unchecked (self . 0 . slice (start .. end)) } else { BytesVec :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> RawTransactionReader < 'r > { RawTransactionReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for RawTransaction { type Builder = RawTransactionBuilder ; const NAME : & 'static str = "RawTransaction" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { RawTransaction (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { RawTransactionReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { RawTransactionReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . version (self . version ()) . cell_deps (self . cell_deps ()) . header_deps (self . header_deps ()) . inputs (self . inputs ()) . outputs (self . outputs ()) . outputs_data (self . outputs_data ()) } } +# [derive (Clone , Copy)] pub struct RawTransactionReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for RawTransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for RawTransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for RawTransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "version" , self . version ()) ? ; write ! (f , ", {}: {}" , "cell_deps" , self . cell_deps ()) ? ; write ! (f , ", {}: {}" , "header_deps" , self . header_deps ()) ? ; write ! (f , ", {}: {}" , "inputs" , self . inputs ()) ? ; write ! (f , ", {}: {}" , "outputs" , self . outputs ()) ? ; write ! (f , ", {}: {}" , "outputs_data" , self . outputs_data ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > RawTransactionReader < 'r > { pub const FIELD_COUNT : usize = 6 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn version (& self) -> Uint32Reader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Uint32Reader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn cell_deps (& self) -> CellDepVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; CellDepVecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn header_deps (& self) -> Byte32VecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; let end = molecule :: unpack_number (& slice [16 ..]) as usize ; Byte32VecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn inputs (& self) -> CellInputVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [16 ..]) as usize ; let end = molecule :: unpack_number (& slice [20 ..]) as usize ; CellInputVecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn outputs (& self) -> CellOutputVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [20 ..]) as usize ; let end = molecule :: unpack_number (& slice [24 ..]) as usize ; CellOutputVecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn outputs_data (& self) -> BytesVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [24 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [28 ..]) as usize ; BytesVecReader :: new_unchecked (& self . as_slice () [start .. end]) } else { BytesVecReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for RawTransactionReader < 'r > { type Entity = RawTransaction ; const NAME : & 'static str = "RawTransactionReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { RawTransactionReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } Uint32Reader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; CellDepVecReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; Byte32VecReader :: verify (& slice [offsets [2] .. offsets [3]] , compatible) ? ; CellInputVecReader :: verify (& slice [offsets [3] .. offsets [4]] , compatible) ? ; CellOutputVecReader :: verify (& slice [offsets [4] .. offsets [5]] , compatible) ? ; BytesVecReader :: verify (& slice [offsets [5] .. offsets [6]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct RawTransactionBuilder { pub (crate) version : Uint32 , pub (crate) cell_deps : CellDepVec , pub (crate) header_deps : Byte32Vec , pub (crate) inputs : CellInputVec , pub (crate) outputs : CellOutputVec , pub (crate) outputs_data : BytesVec , } impl RawTransactionBuilder { pub const FIELD_COUNT : usize = 6 ; pub fn version (mut self , v : Uint32) -> Self { self . version = v ; self } pub fn cell_deps (mut self , v : CellDepVec) -> Self { self . cell_deps = v ; self } pub fn header_deps (mut self , v : Byte32Vec) -> Self { self . header_deps = v ; self } pub fn inputs (mut self , v : CellInputVec) -> Self { self . inputs = v ; self } pub fn outputs (mut self , v : CellOutputVec) -> Self { self . outputs = v ; self } pub fn outputs_data (mut self , v : BytesVec) -> Self { self . outputs_data = v ; self } } impl molecule :: prelude :: Builder for RawTransactionBuilder { type Entity = RawTransaction ; const NAME : & 'static str = "RawTransactionBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . version . as_slice () . len () + self . cell_deps . as_slice () . len () + self . header_deps . as_slice () . len () + self . inputs . as_slice () . len () + self . outputs . as_slice () . len () + self . outputs_data . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . version . as_slice () . len () ; offsets . push (total_size) ; total_size += self . cell_deps . as_slice () . len () ; offsets . push (total_size) ; total_size += self . header_deps . as_slice () . len () ; offsets . push (total_size) ; total_size += self . inputs . as_slice () . len () ; offsets . push (total_size) ; total_size += self . outputs . as_slice () . len () ; offsets . push (total_size) ; total_size += self . outputs_data . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . version . as_slice ()) ? ; writer . write_all (self . cell_deps . as_slice ()) ? ; writer . write_all (self . header_deps . as_slice ()) ? ; writer . write_all (self . inputs . as_slice ()) ? ; writer . write_all (self . outputs . as_slice ()) ? ; writer . write_all (self . outputs_data . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; RawTransaction :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct Transaction (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Transaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Transaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Transaction { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "raw" , self . raw ()) ? ; write ! (f , ", {}: {}" , "witnesses" , self . witnesses ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for Transaction { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Transaction :: new_unchecked (v) } } impl Transaction { const DEFAULT_VALUE : [u8 ; 68] = [68 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 64 , 0 , 0 , 0 , 52 , 0 , 0 , 0 , 28 , 0 , 0 , 0 , 32 , 0 , 0 , 0 , 36 , 0 , 0 , 0 , 40 , 0 , 0 , 0 , 44 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn raw (& self) -> RawTransaction { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; RawTransaction :: new_unchecked (self . 0 . slice (start .. end)) } pub fn witnesses (& self) -> BytesVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; BytesVec :: new_unchecked (self . 0 . slice (start .. end)) } else { BytesVec :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> TransactionReader < 'r > { TransactionReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Transaction { type Builder = TransactionBuilder ; const NAME : & 'static str = "Transaction" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Transaction (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { TransactionReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { TransactionReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . raw (self . raw ()) . witnesses (self . witnesses ()) } } +# [derive (Clone , Copy)] pub struct TransactionReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for TransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for TransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for TransactionReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "raw" , self . raw ()) ? ; write ! (f , ", {}: {}" , "witnesses" , self . witnesses ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > TransactionReader < 'r > { pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn raw (& self) -> RawTransactionReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; RawTransactionReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn witnesses (& self) -> BytesVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; BytesVecReader :: new_unchecked (& self . as_slice () [start .. end]) } else { BytesVecReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for TransactionReader < 'r > { type Entity = Transaction ; const NAME : & 'static str = "TransactionReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { TransactionReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } RawTransactionReader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; BytesVecReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct TransactionBuilder { pub (crate) raw : RawTransaction , pub (crate) witnesses : BytesVec , } impl TransactionBuilder { pub const FIELD_COUNT : usize = 2 ; pub fn raw (mut self , v : RawTransaction) -> Self { self . raw = v ; self } pub fn witnesses (mut self , v : BytesVec) -> Self { self . witnesses = v ; self } } impl molecule :: prelude :: Builder for TransactionBuilder { type Entity = Transaction ; const NAME : & 'static str = "TransactionBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . raw . as_slice () . len () + self . witnesses . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . raw . as_slice () . len () ; offsets . push (total_size) ; total_size += self . witnesses . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . raw . as_slice ()) ? ; writer . write_all (self . witnesses . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Transaction :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct RawHeader (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for RawHeader { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for RawHeader { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for RawHeader { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "version" , self . version ()) ? ; write ! (f , ", {}: {}" , "compact_target" , self . compact_target ()) ? ; write ! (f , ", {}: {}" , "timestamp" , self . timestamp ()) ? ; write ! (f , ", {}: {}" , "number" , self . number ()) ? ; write ! (f , ", {}: {}" , "epoch" , self . epoch ()) ? ; write ! (f , ", {}: {}" , "parent_hash" , self . parent_hash ()) ? ; write ! (f , ", {}: {}" , "transactions_root" , self . transactions_root ()) ? ; write ! (f , ", {}: {}" , "proposals_hash" , self . proposals_hash ()) ? ; write ! (f , ", {}: {}" , "uncles_hash" , self . uncles_hash ()) ? ; write ! (f , ", {}: {}" , "dao" , self . dao ()) ? ; write ! (f , " }}") } } impl :: core :: default :: Default for RawHeader { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; RawHeader :: new_unchecked (v) } } impl RawHeader { const DEFAULT_VALUE : [u8 ; 192] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 192 ; pub const FIELD_SIZES : [usize ; 10] = [4 , 4 , 8 , 8 , 8 , 32 , 32 , 32 , 32 , 32 ,] ; pub const FIELD_COUNT : usize = 10 ; pub fn version (& self) -> Uint32 { Uint32 :: new_unchecked (self . 0 . slice (0 .. 4)) } pub fn compact_target (& self) -> Uint32 { Uint32 :: new_unchecked (self . 0 . slice (4 .. 8)) } pub fn timestamp (& self) -> Uint64 { Uint64 :: new_unchecked (self . 0 . slice (8 .. 16)) } pub fn number (& self) -> Uint64 { Uint64 :: new_unchecked (self . 0 . slice (16 .. 24)) } pub fn epoch (& self) -> Uint64 { Uint64 :: new_unchecked (self . 0 . slice (24 .. 32)) } pub fn parent_hash (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (32 .. 64)) } pub fn transactions_root (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (64 .. 96)) } pub fn proposals_hash (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (96 .. 128)) } pub fn uncles_hash (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (128 .. 160)) } pub fn dao (& self) -> Byte32 { Byte32 :: new_unchecked (self . 0 . slice (160 .. 192)) } pub fn as_reader < 'r > (& 'r self) -> RawHeaderReader < 'r > { RawHeaderReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for RawHeader { type Builder = RawHeaderBuilder ; const NAME : & 'static str = "RawHeader" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { RawHeader (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { RawHeaderReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { RawHeaderReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . version (self . version ()) . compact_target (self . compact_target ()) . timestamp (self . timestamp ()) . number (self . number ()) . epoch (self . epoch ()) . parent_hash (self . parent_hash ()) . transactions_root (self . transactions_root ()) . proposals_hash (self . proposals_hash ()) . uncles_hash (self . uncles_hash ()) . dao (self . dao ()) } } +# [derive (Clone , Copy)] pub struct RawHeaderReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for RawHeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for RawHeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for RawHeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "version" , self . version ()) ? ; write ! (f , ", {}: {}" , "compact_target" , self . compact_target ()) ? ; write ! (f , ", {}: {}" , "timestamp" , self . timestamp ()) ? ; write ! (f , ", {}: {}" , "number" , self . number ()) ? ; write ! (f , ", {}: {}" , "epoch" , self . epoch ()) ? ; write ! (f , ", {}: {}" , "parent_hash" , self . parent_hash ()) ? ; write ! (f , ", {}: {}" , "transactions_root" , self . transactions_root ()) ? ; write ! (f , ", {}: {}" , "proposals_hash" , self . proposals_hash ()) ? ; write ! (f , ", {}: {}" , "uncles_hash" , self . uncles_hash ()) ? ; write ! (f , ", {}: {}" , "dao" , self . dao ()) ? ; write ! (f , " }}") } } impl < 'r > RawHeaderReader < 'r > { pub const TOTAL_SIZE : usize = 192 ; pub const FIELD_SIZES : [usize ; 10] = [4 , 4 , 8 , 8 , 8 , 32 , 32 , 32 , 32 , 32 ,] ; pub const FIELD_COUNT : usize = 10 ; pub fn version (& self) -> Uint32Reader < 'r > { Uint32Reader :: new_unchecked (& self . as_slice () [0 .. 4]) } pub fn compact_target (& self) -> Uint32Reader < 'r > { Uint32Reader :: new_unchecked (& self . as_slice () [4 .. 8]) } pub fn timestamp (& self) -> Uint64Reader < 'r > { Uint64Reader :: new_unchecked (& self . as_slice () [8 .. 16]) } pub fn number (& self) -> Uint64Reader < 'r > { Uint64Reader :: new_unchecked (& self . as_slice () [16 .. 24]) } pub fn epoch (& self) -> Uint64Reader < 'r > { Uint64Reader :: new_unchecked (& self . as_slice () [24 .. 32]) } pub fn parent_hash (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [32 .. 64]) } pub fn transactions_root (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [64 .. 96]) } pub fn proposals_hash (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [96 .. 128]) } pub fn uncles_hash (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [128 .. 160]) } pub fn dao (& self) -> Byte32Reader < 'r > { Byte32Reader :: new_unchecked (& self . as_slice () [160 .. 192]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for RawHeaderReader < 'r > { type Entity = RawHeader ; const NAME : & 'static str = "RawHeaderReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { RawHeaderReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct RawHeaderBuilder { pub (crate) version : Uint32 , pub (crate) compact_target : Uint32 , pub (crate) timestamp : Uint64 , pub (crate) number : Uint64 , pub (crate) epoch : Uint64 , pub (crate) parent_hash : Byte32 , pub (crate) transactions_root : Byte32 , pub (crate) proposals_hash : Byte32 , pub (crate) uncles_hash : Byte32 , pub (crate) dao : Byte32 , } impl RawHeaderBuilder { pub const TOTAL_SIZE : usize = 192 ; pub const FIELD_SIZES : [usize ; 10] = [4 , 4 , 8 , 8 , 8 , 32 , 32 , 32 , 32 , 32 ,] ; pub const FIELD_COUNT : usize = 10 ; pub fn version (mut self , v : Uint32) -> Self { self . version = v ; self } pub fn compact_target (mut self , v : Uint32) -> Self { self . compact_target = v ; self } pub fn timestamp (mut self , v : Uint64) -> Self { self . timestamp = v ; self } pub fn number (mut self , v : Uint64) -> Self { self . number = v ; self } pub fn epoch (mut self , v : Uint64) -> Self { self . epoch = v ; self } pub fn parent_hash (mut self , v : Byte32) -> Self { self . parent_hash = v ; self } pub fn transactions_root (mut self , v : Byte32) -> Self { self . transactions_root = v ; self } pub fn proposals_hash (mut self , v : Byte32) -> Self { self . proposals_hash = v ; self } pub fn uncles_hash (mut self , v : Byte32) -> Self { self . uncles_hash = v ; self } pub fn dao (mut self , v : Byte32) -> Self { self . dao = v ; self } } impl molecule :: prelude :: Builder for RawHeaderBuilder { type Entity = RawHeader ; const NAME : & 'static str = "RawHeaderBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . version . as_slice ()) ? ; writer . write_all (self . compact_target . as_slice ()) ? ; writer . write_all (self . timestamp . as_slice ()) ? ; writer . write_all (self . number . as_slice ()) ? ; writer . write_all (self . epoch . as_slice ()) ? ; writer . write_all (self . parent_hash . as_slice ()) ? ; writer . write_all (self . transactions_root . as_slice ()) ? ; writer . write_all (self . proposals_hash . as_slice ()) ? ; writer . write_all (self . uncles_hash . as_slice ()) ? ; writer . write_all (self . dao . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; RawHeader :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct Header (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Header { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Header { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Header { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "raw" , self . raw ()) ? ; write ! (f , ", {}: {}" , "nonce" , self . nonce ()) ? ; write ! (f , " }}") } } impl :: core :: default :: Default for Header { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Header :: new_unchecked (v) } } impl Header { const DEFAULT_VALUE : [u8 ; 208] = [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const TOTAL_SIZE : usize = 208 ; pub const FIELD_SIZES : [usize ; 2] = [192 , 16 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn raw (& self) -> RawHeader { RawHeader :: new_unchecked (self . 0 . slice (0 .. 192)) } pub fn nonce (& self) -> Uint128 { Uint128 :: new_unchecked (self . 0 . slice (192 .. 208)) } pub fn as_reader < 'r > (& 'r self) -> HeaderReader < 'r > { HeaderReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Header { type Builder = HeaderBuilder ; const NAME : & 'static str = "Header" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Header (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { HeaderReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { HeaderReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . raw (self . raw ()) . nonce (self . nonce ()) } } +# [derive (Clone , Copy)] pub struct HeaderReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for HeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for HeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for HeaderReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "raw" , self . raw ()) ? ; write ! (f , ", {}: {}" , "nonce" , self . nonce ()) ? ; write ! (f , " }}") } } impl < 'r > HeaderReader < 'r > { pub const TOTAL_SIZE : usize = 208 ; pub const FIELD_SIZES : [usize ; 2] = [192 , 16 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn raw (& self) -> RawHeaderReader < 'r > { RawHeaderReader :: new_unchecked (& self . as_slice () [0 .. 192]) } pub fn nonce (& self) -> Uint128Reader < 'r > { Uint128Reader :: new_unchecked (& self . as_slice () [192 .. 208]) } } impl < 'r > molecule :: prelude :: Reader < 'r > for HeaderReader < 'r > { type Entity = Header ; const NAME : & 'static str = "HeaderReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { HeaderReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , _compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len != Self :: TOTAL_SIZE { return ve ! (Self , TotalSizeNotMatch , Self :: TOTAL_SIZE , slice_len) ; } Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct HeaderBuilder { pub (crate) raw : RawHeader , pub (crate) nonce : Uint128 , } impl HeaderBuilder { pub const TOTAL_SIZE : usize = 208 ; pub const FIELD_SIZES : [usize ; 2] = [192 , 16 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn raw (mut self , v : RawHeader) -> Self { self . raw = v ; self } pub fn nonce (mut self , v : Uint128) -> Self { self . nonce = v ; self } } impl molecule :: prelude :: Builder for HeaderBuilder { type Entity = Header ; const NAME : & 'static str = "HeaderBuilder" ; fn expected_length (& self) -> usize { Self :: TOTAL_SIZE } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { writer . write_all (self . raw . as_slice ()) ? ; writer . write_all (self . nonce . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Header :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct UncleBlock (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for UncleBlock { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for UncleBlock { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for UncleBlock { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "header" , self . header ()) ? ; write ! (f , ", {}: {}" , "proposals" , self . proposals ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for UncleBlock { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; UncleBlock :: new_unchecked (v) } } impl UncleBlock { const DEFAULT_VALUE : [u8 ; 224] = [224 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 220 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn header (& self) -> Header { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Header :: new_unchecked (self . 0 . slice (start .. end)) } pub fn proposals (& self) -> ProposalShortIdVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; ProposalShortIdVec :: new_unchecked (self . 0 . slice (start .. end)) } else { ProposalShortIdVec :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> UncleBlockReader < 'r > { UncleBlockReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for UncleBlock { type Builder = UncleBlockBuilder ; const NAME : & 'static str = "UncleBlock" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { UncleBlock (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { UncleBlockReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { UncleBlockReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . header (self . header ()) . proposals (self . proposals ()) } } +# [derive (Clone , Copy)] pub struct UncleBlockReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for UncleBlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for UncleBlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for UncleBlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "header" , self . header ()) ? ; write ! (f , ", {}: {}" , "proposals" , self . proposals ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > UncleBlockReader < 'r > { pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn header (& self) -> HeaderReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; HeaderReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn proposals (& self) -> ProposalShortIdVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; ProposalShortIdVecReader :: new_unchecked (& self . as_slice () [start .. end]) } else { ProposalShortIdVecReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for UncleBlockReader < 'r > { type Entity = UncleBlock ; const NAME : & 'static str = "UncleBlockReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { UncleBlockReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } HeaderReader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; ProposalShortIdVecReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct UncleBlockBuilder { pub (crate) header : Header , pub (crate) proposals : ProposalShortIdVec , } impl UncleBlockBuilder { pub const FIELD_COUNT : usize = 2 ; pub fn header (mut self , v : Header) -> Self { self . header = v ; self } pub fn proposals (mut self , v : ProposalShortIdVec) -> Self { self . proposals = v ; self } } impl molecule :: prelude :: Builder for UncleBlockBuilder { type Entity = UncleBlock ; const NAME : & 'static str = "UncleBlockBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . header . as_slice () . len () + self . proposals . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . header . as_slice () . len () ; offsets . push (total_size) ; total_size += self . proposals . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . header . as_slice ()) ? ; writer . write_all (self . proposals . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; UncleBlock :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct Block (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for Block { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for Block { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for Block { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "header" , self . header ()) ? ; write ! (f , ", {}: {}" , "uncles" , self . uncles ()) ? ; write ! (f , ", {}: {}" , "transactions" , self . transactions ()) ? ; write ! (f , ", {}: {}" , "proposals" , self . proposals ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for Block { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; Block :: new_unchecked (v) } } impl Block { const DEFAULT_VALUE : [u8 ; 240] = [240 , 0 , 0 , 0 , 20 , 0 , 0 , 0 , 228 , 0 , 0 , 0 , 232 , 0 , 0 , 0 , 236 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 4 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn header (& self) -> Header { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Header :: new_unchecked (self . 0 . slice (start .. end)) } pub fn uncles (& self) -> UncleBlockVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; UncleBlockVec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn transactions (& self) -> TransactionVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; let end = molecule :: unpack_number (& slice [16 ..]) as usize ; TransactionVec :: new_unchecked (self . 0 . slice (start .. end)) } pub fn proposals (& self) -> ProposalShortIdVec { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [16 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [20 ..]) as usize ; ProposalShortIdVec :: new_unchecked (self . 0 . slice (start .. end)) } else { ProposalShortIdVec :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> BlockReader < 'r > { BlockReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for Block { type Builder = BlockBuilder ; const NAME : & 'static str = "Block" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { Block (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BlockReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { BlockReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . header (self . header ()) . uncles (self . uncles ()) . transactions (self . transactions ()) . proposals (self . proposals ()) } } +# [derive (Clone , Copy)] pub struct BlockReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for BlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for BlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for BlockReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "header" , self . header ()) ? ; write ! (f , ", {}: {}" , "uncles" , self . uncles ()) ? ; write ! (f , ", {}: {}" , "transactions" , self . transactions ()) ? ; write ! (f , ", {}: {}" , "proposals" , self . proposals ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > BlockReader < 'r > { pub const FIELD_COUNT : usize = 4 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn header (& self) -> HeaderReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; HeaderReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn uncles (& self) -> UncleBlockVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; UncleBlockVecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn transactions (& self) -> TransactionVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; let end = molecule :: unpack_number (& slice [16 ..]) as usize ; TransactionVecReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn proposals (& self) -> ProposalShortIdVecReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [16 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [20 ..]) as usize ; ProposalShortIdVecReader :: new_unchecked (& self . as_slice () [start .. end]) } else { ProposalShortIdVecReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for BlockReader < 'r > { type Entity = Block ; const NAME : & 'static str = "BlockReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { BlockReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } HeaderReader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; UncleBlockVecReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; TransactionVecReader :: verify (& slice [offsets [2] .. offsets [3]] , compatible) ? ; ProposalShortIdVecReader :: verify (& slice [offsets [3] .. offsets [4]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct BlockBuilder { pub (crate) header : Header , pub (crate) uncles : UncleBlockVec , pub (crate) transactions : TransactionVec , pub (crate) proposals : ProposalShortIdVec , } impl BlockBuilder { pub const FIELD_COUNT : usize = 4 ; pub fn header (mut self , v : Header) -> Self { self . header = v ; self } pub fn uncles (mut self , v : UncleBlockVec) -> Self { self . uncles = v ; self } pub fn transactions (mut self , v : TransactionVec) -> Self { self . transactions = v ; self } pub fn proposals (mut self , v : ProposalShortIdVec) -> Self { self . proposals = v ; self } } impl molecule :: prelude :: Builder for BlockBuilder { type Entity = Block ; const NAME : & 'static str = "BlockBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . header . as_slice () . len () + self . uncles . as_slice () . len () + self . transactions . as_slice () . len () + self . proposals . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . header . as_slice () . len () ; offsets . push (total_size) ; total_size += self . uncles . as_slice () . len () ; offsets . push (total_size) ; total_size += self . transactions . as_slice () . len () ; offsets . push (total_size) ; total_size += self . proposals . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . header . as_slice ()) ? ; writer . write_all (self . uncles . as_slice ()) ? ; writer . write_all (self . transactions . as_slice ()) ? ; writer . write_all (self . proposals . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; Block :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct CellbaseWitness (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for CellbaseWitness { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for CellbaseWitness { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for CellbaseWitness { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "message" , self . message ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for CellbaseWitness { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; CellbaseWitness :: new_unchecked (v) } } impl CellbaseWitness { const DEFAULT_VALUE : [u8 ; 69] = [69 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 65 , 0 , 0 , 0 , 53 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 49 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn lock (& self) -> Script { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; Script :: new_unchecked (self . 0 . slice (start .. end)) } pub fn message (& self) -> Bytes { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; Bytes :: new_unchecked (self . 0 . slice (start .. end)) } else { Bytes :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> CellbaseWitnessReader < 'r > { CellbaseWitnessReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for CellbaseWitness { type Builder = CellbaseWitnessBuilder ; const NAME : & 'static str = "CellbaseWitness" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { CellbaseWitness (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellbaseWitnessReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { CellbaseWitnessReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . lock (self . lock ()) . message (self . message ()) } } +# [derive (Clone , Copy)] pub struct CellbaseWitnessReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for CellbaseWitnessReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for CellbaseWitnessReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for CellbaseWitnessReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "message" , self . message ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > CellbaseWitnessReader < 'r > { pub const FIELD_COUNT : usize = 2 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn lock (& self) -> ScriptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; ScriptReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn message (& self) -> BytesReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [12 ..]) as usize ; BytesReader :: new_unchecked (& self . as_slice () [start .. end]) } else { BytesReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for CellbaseWitnessReader < 'r > { type Entity = CellbaseWitness ; const NAME : & 'static str = "CellbaseWitnessReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { CellbaseWitnessReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } ScriptReader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; BytesReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct CellbaseWitnessBuilder { pub (crate) lock : Script , pub (crate) message : Bytes , } impl CellbaseWitnessBuilder { pub const FIELD_COUNT : usize = 2 ; pub fn lock (mut self , v : Script) -> Self { self . lock = v ; self } pub fn message (mut self , v : Bytes) -> Self { self . message = v ; self } } impl molecule :: prelude :: Builder for CellbaseWitnessBuilder { type Entity = CellbaseWitness ; const NAME : & 'static str = "CellbaseWitnessBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . lock . as_slice () . len () + self . message . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . lock . as_slice () . len () ; offsets . push (total_size) ; total_size += self . message . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . lock . as_slice ()) ? ; writer . write_all (self . message . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; CellbaseWitness :: new_unchecked (inner . into ()) } } +# [derive (Clone)] pub struct WitnessArgs (molecule :: bytes :: Bytes) ; impl :: core :: fmt :: LowerHex for WitnessArgs { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl :: core :: fmt :: Debug for WitnessArgs { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl :: core :: fmt :: Display for WitnessArgs { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "input_type" , self . input_type ()) ? ; write ! (f , ", {}: {}" , "output_type" , self . output_type ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl :: core :: default :: Default for WitnessArgs { fn default () -> Self { let v = molecule :: bytes :: Bytes :: from_static (& Self :: DEFAULT_VALUE) ; WitnessArgs :: new_unchecked (v) } } impl WitnessArgs { const DEFAULT_VALUE : [u8 ; 16] = [16 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 16 , 0 , 0 , 0 ,] ; pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn lock (& self) -> BytesOpt { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; BytesOpt :: new_unchecked (self . 0 . slice (start .. end)) } pub fn input_type (& self) -> BytesOpt { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; BytesOpt :: new_unchecked (self . 0 . slice (start .. end)) } pub fn output_type (& self) -> BytesOpt { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; BytesOpt :: new_unchecked (self . 0 . slice (start .. end)) } else { BytesOpt :: new_unchecked (self . 0 . slice (start ..)) } } pub fn as_reader < 'r > (& 'r self) -> WitnessArgsReader < 'r > { WitnessArgsReader :: new_unchecked (self . as_slice ()) } } impl molecule :: prelude :: Entity for WitnessArgs { type Builder = WitnessArgsBuilder ; const NAME : & 'static str = "WitnessArgs" ; fn new_unchecked (data : molecule :: bytes :: Bytes) -> Self { WitnessArgs (data) } fn as_bytes (& self) -> molecule :: bytes :: Bytes { self . 0 . clone () } fn as_slice (& self) -> & [u8] { & self . 0 [..] } fn from_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { WitnessArgsReader :: from_slice (slice) . map (| reader | reader . to_entity ()) } fn from_compatible_slice (slice : & [u8]) -> molecule :: error :: VerificationResult < Self > { WitnessArgsReader :: from_compatible_slice (slice) . map (| reader | reader . to_entity ()) } fn new_builder () -> Self :: Builder { :: core :: default :: Default :: default () } fn as_builder (self) -> Self :: Builder { Self :: new_builder () . lock (self . lock ()) . input_type (self . input_type ()) . output_type (self . output_type ()) } } +# [derive (Clone , Copy)] pub struct WitnessArgsReader < 'r > (& 'r [u8]) ; impl < 'r > :: core :: fmt :: LowerHex for WitnessArgsReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { use molecule :: hex_string ; if f . alternate () { write ! (f , "0x") ? ; } write ! (f , "{}" , hex_string (self . as_slice ())) } } impl < 'r > :: core :: fmt :: Debug for WitnessArgsReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{}({:#x})" , Self :: NAME , self) } } impl < 'r > :: core :: fmt :: Display for WitnessArgsReader < 'r > { fn fmt (& self , f : & mut :: core :: fmt :: Formatter) -> :: core :: fmt :: Result { write ! (f , "{} {{ " , Self :: NAME) ? ; write ! (f , "{}: {}" , "lock" , self . lock ()) ? ; write ! (f , ", {}: {}" , "input_type" , self . input_type ()) ? ; write ! (f , ", {}: {}" , "output_type" , self . output_type ()) ? ; let extra_count = self . count_extra_fields () ; if extra_count != 0 { write ! (f , ", .. ({} fields)" , extra_count) ? ; } write ! (f , " }}") } } impl < 'r > WitnessArgsReader < 'r > { pub const FIELD_COUNT : usize = 3 ; pub fn total_size (& self) -> usize { molecule :: unpack_number (self . as_slice ()) as usize } pub fn field_count (& self) -> usize { if self . total_size () == molecule :: NUMBER_SIZE { 0 } else { (molecule :: unpack_number (& self . as_slice () [molecule :: NUMBER_SIZE ..]) as usize / 4) - 1 } } pub fn count_extra_fields (& self) -> usize { self . field_count () - Self :: FIELD_COUNT } pub fn has_extra_fields (& self) -> bool { Self :: FIELD_COUNT != self . field_count () } pub fn lock (& self) -> BytesOptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [4 ..]) as usize ; let end = molecule :: unpack_number (& slice [8 ..]) as usize ; BytesOptReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn input_type (& self) -> BytesOptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [8 ..]) as usize ; let end = molecule :: unpack_number (& slice [12 ..]) as usize ; BytesOptReader :: new_unchecked (& self . as_slice () [start .. end]) } pub fn output_type (& self) -> BytesOptReader < 'r > { let slice = self . as_slice () ; let start = molecule :: unpack_number (& slice [12 ..]) as usize ; if self . has_extra_fields () { let end = molecule :: unpack_number (& slice [16 ..]) as usize ; BytesOptReader :: new_unchecked (& self . as_slice () [start .. end]) } else { BytesOptReader :: new_unchecked (& self . as_slice () [start ..]) } } } impl < 'r > molecule :: prelude :: Reader < 'r > for WitnessArgsReader < 'r > { type Entity = WitnessArgs ; const NAME : & 'static str = "WitnessArgsReader" ; fn to_entity (& self) -> Self :: Entity { Self :: Entity :: new_unchecked (self . as_slice () . to_owned () . into ()) } fn new_unchecked (slice : & 'r [u8]) -> Self { WitnessArgsReader (slice) } fn as_slice (& self) -> & 'r [u8] { self . 0 } fn verify (slice : & [u8] , compatible : bool) -> molecule :: error :: VerificationResult < () > { use molecule :: verification_error as ve ; let slice_len = slice . len () ; if slice_len < molecule :: NUMBER_SIZE { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE , slice_len) ; } let total_size = molecule :: unpack_number (slice) as usize ; if slice_len != total_size { return ve ! (Self , TotalSizeNotMatch , total_size , slice_len) ; } if slice_len < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , HeaderIsBroken , molecule :: NUMBER_SIZE * 2 , slice_len) ; } let offset_first = molecule :: unpack_number (& slice [molecule :: NUMBER_SIZE ..]) as usize ; if offset_first % molecule :: NUMBER_SIZE != 0 || offset_first < molecule :: NUMBER_SIZE * 2 { return ve ! (Self , OffsetsNotMatch) ; } if slice_len < offset_first { return ve ! (Self , HeaderIsBroken , offset_first , slice_len) ; } let field_count = offset_first / molecule :: NUMBER_SIZE - 1 ; if field_count < Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } else if ! compatible && field_count > Self :: FIELD_COUNT { return ve ! (Self , FieldCountNotMatch , Self :: FIELD_COUNT , field_count) ; } ; let mut offsets : Vec < usize > = slice [molecule :: NUMBER_SIZE .. offset_first] . chunks_exact (molecule :: NUMBER_SIZE) . map (| x | molecule :: unpack_number (x) as usize) . collect () ; offsets . push (total_size) ; if offsets . windows (2) . any (| i | i [0] > i [1]) { return ve ! (Self , OffsetsNotMatch) ; } BytesOptReader :: verify (& slice [offsets [0] .. offsets [1]] , compatible) ? ; BytesOptReader :: verify (& slice [offsets [1] .. offsets [2]] , compatible) ? ; BytesOptReader :: verify (& slice [offsets [2] .. offsets [3]] , compatible) ? ; Ok (()) } } +# [derive (Clone , Debug , Default)] pub struct WitnessArgsBuilder { pub (crate) lock : BytesOpt , pub (crate) input_type : BytesOpt , pub (crate) output_type : BytesOpt , } impl WitnessArgsBuilder { pub const FIELD_COUNT : usize = 3 ; pub fn lock (mut self , v : BytesOpt) -> Self { self . lock = v ; self } pub fn input_type (mut self , v : BytesOpt) -> Self { self . input_type = v ; self } pub fn output_type (mut self , v : BytesOpt) -> Self { self . output_type = v ; self } } impl molecule :: prelude :: Builder for WitnessArgsBuilder { type Entity = WitnessArgs ; const NAME : & 'static str = "WitnessArgsBuilder" ; fn expected_length (& self) -> usize { molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) + self . lock . as_slice () . len () + self . input_type . as_slice () . len () + self . output_type . as_slice () . len () } fn write < W : molecule :: io :: Write > (& self , writer : & mut W) -> molecule :: io :: Result < () > { let mut total_size = molecule :: NUMBER_SIZE * (Self :: FIELD_COUNT + 1) ; let mut offsets = Vec :: with_capacity (Self :: FIELD_COUNT) ; offsets . push (total_size) ; total_size += self . lock . as_slice () . len () ; offsets . push (total_size) ; total_size += self . input_type . as_slice () . len () ; offsets . push (total_size) ; total_size += self . output_type . as_slice () . len () ; writer . write_all (& molecule :: pack_number (total_size as molecule :: Number)) ? ; for offset in offsets . into_iter () { writer . write_all (& molecule :: pack_number (offset as molecule :: Number)) ? ; } writer . write_all (self . lock . as_slice ()) ? ; writer . write_all (self . input_type . as_slice ()) ? ; writer . write_all (self . output_type . as_slice ()) ? ; Ok (()) } fn build (& self) -> Self :: Entity { let mut inner = Vec :: with_capacity (self . expected_length ()) ; self . write (& mut inner) . unwrap_or_else (| _ | panic ! ("{} build should be ok" , Self :: NAME)) ; WitnessArgs :: new_unchecked (inner . into ()) } } diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/src/channels.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/channels.rs new file mode 100644 index 0000000..293c57b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/channels.rs @@ -0,0 +1,217 @@ +use crate::error::Error; +use crate::helpers::blake2b256; +use crate::perun_types::{ChannelParameters, ChannelStatus, ChannelToken, VirtualChannelStatus}; + +extern crate alloc; + +use ckb_std::{ + ckb_constants::Source, + ckb_types::{packed::Byte32, prelude::*}, + debug, + high_level::{ + load_cell_data, load_cell_lock_hash, load_cell_type_hash, load_header, load_transaction, + }, + syscalls::{self, SysError}, +}; + +pub enum VChannelAction { + /// Progress indicates that a higher version of virtual channel may be registered + Progress { + old_status: VirtualChannelStatus, + new_status: VirtualChannelStatus, + }, // one PCTS input, one PCTS output + + /// Start indicates that a lc channel is being disputed and a vc cell is created for the first time in the outputs + Start { + new_vc_status: VirtualChannelStatus, + old_lc_status: ChannelStatus, + new_lc_status: ChannelStatus, + }, // no VCTS input, one VCTS output + /// Merge indicates that two virtual channels are being merged into a single one + Merge { + input_vc_status1: VirtualChannelStatus, + input_vc_status2: VirtualChannelStatus, + merged_vc_status: VirtualChannelStatus, + }, + /// Close1 indicates that one of the parents of the virtual channel is being closed + Close1 { + input_vc_status: VirtualChannelStatus, + output_vc_status: VirtualChannelStatus, + }, + /// Close2 indicates that 2nd parent of the virtual channel and the virtual channel itself is being closed + Close2 { + input_lc_status: ChannelStatus, + input_vc_status: VirtualChannelStatus, + }, + // Close indicates that a channel is being closed. This means that a channel's cell is consumed without being + // recreated in the outputs with updated state. The possible redeemers associated with the Close action are + // Close, Abort and ForceClose. + // The channel type script assures that all funds are paid out to the correct parties upon closing. + //Close { old_status: VirtualChannelStatus }, // one PCTS input, no PCTS output +} + +pub enum PChannelAction { + /// Progress indicates that a channel is being progressed. This means that a channel cell is consumed + /// in the inputs and the same channel with updated state is progressed in the outputs. + /// The possible redeemers associated with the Progress action are Fund and Dispute. + Progress { + old_status: ChannelStatus, + new_status: ChannelStatus, + }, // one PCTS input, one PCTS output + /// Start indicates that a channel is being started. This means that a **new channel** lives in the + /// output cells of this transaction. No channel cell is consumes as an input. + /// As Start does not consume a channel cell, there is no Witness associated with the Start action. + Start { new_status: ChannelStatus }, // no PCTS input, one PCTS output + /// Close indicates that a channel is being closed. This means that a channel's cell is consumed without being + /// recreated in the outputs with updated state. The possible redeemers associated with the Close action are + /// Close, Abort and ForceClose. + /// The channel type script assures that all funds are paid out to the correct parties upon closing. + Close { old_status: ChannelStatus }, // one PCTS input , no PCTS output +} + +pub fn get_channel_action() -> Result { + let input_status_opt = load_cell_data(0, Source::GroupInput) + .ok() + .map(|data| ChannelStatus::from_slice(data.as_slice())) + .map_or(Ok(None), |v| v.map(Some))?; + + let output_status_opt = load_cell_data(0, Source::GroupOutput) + .ok() + .map(|data| ChannelStatus::from_slice(data.as_slice())) + .map_or(Ok(None), |v| v.map(Some))?; + + debug!("input_status_opt: {:?}", input_status_opt); + debug!("output_status_opt: {:?}", output_status_opt); + + match (input_status_opt, output_status_opt) { + (Some(old_status), Some(new_status)) => Ok(PChannelAction::Progress { + old_status, + new_status, + }), + (Some(old_status), None) => Ok(PChannelAction::Close { old_status }), + (None, Some(new_status)) => Ok(PChannelAction::Start { new_status }), + (None, None) => Err(Error::UnableToLoadAnyChannelStatus), + } +} + +/// +/// # Arguments +/// * `party_a_unlock_hash` - The lock hash of the unlock script of party A +/// * `party_b_unlock_script_hash` - The lock hash of the unlock script of party B +/// * `source` - the source for data (Input, Output, GroupInput, GroupOutput, etc.) +/// # Returns +/// * `Ok(())` if the input cell with the given lock hash is found +/// * `Err(Error)` if the input cell with the given lock hash is not found +pub fn find_cell_by_lock_hash( + party_a_unlock_hash: &[u8; 32], + party_b_unlock_script_hash: &[u8; 32], + source: Source, +) -> Result, Error> { + for i in 0.. { + let lock_hash = match load_cell_lock_hash(i, source) { + Ok(lock_hash) => lock_hash, + Err(SysError::IndexOutOfBound) => break, + Err(err) => return Err(err.into()), + }; + if &lock_hash == party_a_unlock_hash || &lock_hash == party_b_unlock_script_hash { + return Ok(Some(i)); + } + } + Ok(None) +} + +pub fn find_cell_by_type_hash( + pcts_hash: &[u8; 32], + source: Source, +) -> Result, Error> { + for i in 0.. { + let type_hash = match load_cell_type_hash(i, source) { + Ok(Some(script)) => script, + Ok(None) => continue, + Err(SysError::IndexOutOfBound) => break, + Err(err) => return Err(err.into()), + }; + if &type_hash == pcts_hash { + return Ok(Some(i)); + } + } + Ok(None) +} + +pub fn verify_channel_id_integrity( + channel_id: &Byte32, + params: &ChannelParameters, +) -> Result<(), Error> { + let digest = blake2b256(params.as_slice()); + let channel_id_bytes: [u8; 32] = channel_id.unpack(); + if digest[..] != channel_id_bytes[..] { + return Err(Error::InvalidChannelId); + } + Ok(()) +} + +pub fn verify_thread_token_integrity(thread_token: &ChannelToken) -> Result<(), Error> { + let inputs = load_transaction()?.raw().inputs(); + for input in inputs.into_iter() { + if input.previous_output().as_slice()[..] == thread_token.out_point().as_slice()[..] { + return Ok(()); + } + } + Err(Error::InvalidThreadToken) +} + +pub fn verify_time_lock_expired(time_lock: u64) -> Result<(), Error> { + let old_header = load_header(0, Source::GroupInput)?; + let old_timestamp: u64 = old_header.raw().timestamp().unpack(); + let current_time = find_closest_current_time(); + if old_timestamp + time_lock > current_time { + return Err(Error::TimeLockNotExpired); + } + Ok(()) +} + +pub fn find_closest_current_time() -> u64 { + let mut latest_time = 0; + for i in 0.. { + match load_header(i, Source::HeaderDep) { + Ok(header) => { + let timestamp = header.raw().timestamp().unpack(); + if timestamp > latest_time { + latest_time = timestamp; + } + } + Err(_) => break, + } + } + latest_time +} + +// verify_max_one_channel verifies that there is at most one channel in the group input and group output respectively. +pub fn verify_max_one_channel() -> Result<(), Error> { + if count_cells(Source::GroupInput)? > 1 || count_cells(Source::GroupOutput)? > 1 { + return Err(Error::MoreThanOneChannel); + } else { + return Ok(()); + } +} + +pub fn count_cells(source: Source) -> Result { + let mut null_buf: [u8; 0] = []; + for i in 0.. { + match syscalls::load_cell(&mut null_buf, 0, i, source) { + Ok(_) => continue, + Err(SysError::LengthNotEnough(_)) => continue, + Err(SysError::IndexOutOfBound) => return Ok(i), + Err(err) => return Err(err.into()), + } + } + Ok(0) +} + +pub fn unpack_u64>(t: &T) -> u64 { + t.unpack() +} + +pub fn unpack_byte32>(t: &T) -> [u8; 32] { + t.unpack() +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/error.rs similarity index 61% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs rename to payment-channel-ckb/devnet/contracts/crates/perun-common/src/error.rs index c40a0e7..f4d5988 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/error.rs @@ -13,7 +13,15 @@ pub enum Error { ItemMissing, LengthNotEnough, Encoding, + WaitFailure, + InvalidFd, + OtherEndClosed, + MaxVmsSpawned, + MaxFdsCreated, + UnexpectedSysError, + TypeIDError, // Verification Errors + InvalidDisputeMode, TotalSizeNotMatch, HeaderIsBroken, UnknownItem, @@ -38,21 +46,32 @@ pub enum Error { MultipleMatchingOutputs, FundsInInputs, AppChannelsNotSupported, - NonLedgerChannelsNotSupported, - VirtualChannelsNotSupported, + UndefinedBehavior, + ChannelCellDataIsEmpty, + // NonLedgerChannelsNotSupported, + // VirtualChannelsNotSupported, ChannelStateNotEqual, FundingChanged, + InvalidParentPCTSHash, + TypeHashNotFound, + LedgerChannelDoesNotHaveEnoughFundsForVC, + UnequalBalanceInLockedFundsAndVirtualChannelBalance, + ParentsOfVCInOutputHaveDifferentVCStatus, + InvalidOutputTxForVCDisputeStart, + OnlyChannelStatusExpectedButThatIsNotTheCase, + InputCellForGivenParticipantNotFound, FundingNotInStatus, OwnFundingNotInOutputs, FundedBitStatusNotCorrect, StateIsFunded, - + ParentPCTSHashNotFound, ChannelFundWithoutChannelOutput, ChannelDisputeWithoutChannelOutput, ChannelCloseWithChannelOutput, ChannelForceCloseWithChannelOutput, ChannelAbortWithChannelOutput, - + InvalidParentsCountForVC, + OutputCellForGivenParticipantNotFound, InvalidThreadToken, InvalidChannelId, StartWithNonZeroVersion, @@ -60,16 +79,19 @@ pub enum Error { InvalidPCLSCodeHash, InvalidPCLSHashType, PCLSWithArgs, + VCLSWithArgs, StatusDisputed, StatusNotDisputed, FundingNotZero, - NotAllPayed, + NotAllPaid, TimeLockNotExpired, InvalidTimestamp, UnableToLoadAnyChannelStatus, + UnableToLoadVirtualChannelStatus, InvalidSignature, InvalidMessage, InvalidPFLSInOutputs, + InvalidNumberOfOutputs, PCTSNotFound, FoundDifferentChannel, MoreThanOneChannel, @@ -80,17 +102,48 @@ pub enum Error { InvalidSUDT, InvalidSUDTDataLength, DecreasingAmount, + WrongChannelType, + InvalidVCTx, + InvalidVCTxStart, + ParentsOfVCNotFound, + VCInputCellMissingInMergeTx, + FundsForVCNotLocked, + InvalidVCMergeTx, + FirstForceCloseFlagSet, + FirstForceCloseFlagNotSet, + InvalidVCLockScript, + ParentNotFoundInOutputs, + InvalidVersionNumberVCProgressTx, + InvalidVCClose1Tx, + ParentsLengthMismatch, + ParentsMismatch, + ParentNotInForceClose, + VCInputCellMissingInClose1Tx, + VCParticipantIdxNotFound, + InvalidVCParentData, + SUDTAllocationLengthMismatch, + VCOutputCellMissingIngStartTx, + VCDisputeWithoutChannelOutput, + VCStatusNotEqual, + NoVCRentPayoutCell, + InvalidVCRentPayoutCell, } impl From for Error { fn from(err: SysError) -> Self { use SysError::*; match err { + MaxFdsCreated => Self::MaxFdsCreated, + MaxVmsSpawned => Self::MaxVmsSpawned, + OtherEndClosed => Self::OtherEndClosed, + InvalidFd => Self::InvalidFd, + WaitFailure => Self::WaitFailure, IndexOutOfBound => Self::IndexOutOfBound, ItemMissing => Self::ItemMissing, LengthNotEnough(_) => Self::LengthNotEnough, Encoding => Self::Encoding, Unknown(err_code) => panic!("unexpected sys error {}", err_code), + _TypeIDError => Self::TypeIDError, } } } diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/helpers.rs similarity index 60% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs rename to payment-channel-ckb/devnet/contracts/crates/perun-common/src/helpers.rs index e5f6e79..c2633d6 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/helpers.rs @@ -8,13 +8,13 @@ use { #[cfg(not(feature = "std"))] use { - ckb_standalone_types::packed::*, - ckb_standalone_types::prelude::*, + ckb_gen_types::packed::*, + ckb_gen_types::prelude::*, molecule::prelude::{vec, Vec}, }; use crate::perun_types::{ - Balances, Bool, BoolUnion, ChannelParameters, ChannelStatus, SEC1EncodedPubKey, + Balances, Bool, BoolUnion, ChannelParameters, ChannelStatus, SEC1EncodedPubKey, SubBalances, }; use crate::{ error::Error, @@ -109,6 +109,24 @@ macro_rules! dispute { }; } +#[macro_export] +macro_rules! vc_dispute { + ($sig_vc_a:expr, $sig_vc_b:expr, $sig_lc_a:expr, $sig_lc_b:expr) => { + $crate::perun_types::ChannelWitnessUnion::VCDispute( + $crate::perun_types::VCDispute::new_builder() + .sig_a($sig_vc_a) + .sig_b($sig_vc_b) + .parent_state_sigs( + $crate::perun_types::Dispute::new_builder() + .sig_a($sig_lc_a) + .sig_b($sig_lc_b) + .build(), + ) + .build(), + ) + }; +} + impl SUDTDistribution { pub fn sum(&self) -> u128 { let a: u128 = self.nth0().unpack(); @@ -200,7 +218,20 @@ impl Balances { } pub fn equal_in_sum(&self, other: &Balances) -> Result { - if self.ckbytes().sum() != other.ckbytes().sum() { + let self_total_ckbytes = self.ckbytes().sum() + + self + .locked() + .into_iter() + .map(|sub_alloc| sub_alloc.balances().ckbytes().sum()) + .sum::(); + let other_total_ckbytes = other.ckbytes().sum() + + other + .locked() + .into_iter() + .map(|sub_alloc| sub_alloc.balances().ckbytes().sum()) + .sum::(); + + if self_total_ckbytes != other_total_ckbytes { return Ok(false); } if self.sudts().len() != other.sudts().len() { @@ -211,11 +242,32 @@ impl Balances { if sb.asset().as_slice() != other_sb.asset().as_slice() { return Ok(false); } - if sb.distribution().sum() != other_sb.distribution().sum() { + + // Sum `sudts` including locked balances + let mut self_total_amount = sb.distribution().sum(); + let mut other_total_amount = other_sb.distribution().sum(); + + for sub_alloc in self.locked().into_iter() { + for sub_sb in sub_alloc.balances().sudts().into_iter() { + if sub_sb.asset().as_slice() == sb.asset().as_slice() { + self_total_amount += sub_sb.distribution().sum(); + } + } + } + + for sub_alloc in other.locked().into_iter() { + for sub_sb in sub_alloc.balances().sudts().into_iter() { + if sub_sb.asset().as_slice() == other_sb.asset().as_slice() { + other_total_amount += sub_sb.distribution().sum(); + } + } + } + + if self_total_amount != other_total_amount { return Ok(false); } } - return Ok(true); + Ok(true) } pub fn equal(&self, other: &Balances) -> bool { @@ -254,6 +306,32 @@ impl SUDTAllocation { } return Ok(true); } + + pub fn fully_represented_vc( + &self, + lc_participant_idx: usize, + vc_participant_idx: usize, + vc_sudts: &SUDTAllocation, + values: &[u128], + ) -> Result { + if values.len() < self.len() { + return Ok(false); + } + if self.len() != vc_sudts.len() { + return Err(Error::SUDTAllocationLengthMismatch); + } + for (i, sudt_balances_lc) in self.clone().into_iter().enumerate() { + let lc_balance = sudt_balances_lc.distribution().get(lc_participant_idx)?; + let (_, vc_distribution) = + vc_sudts.get_distribution(&sudt_balances_lc.asset().type_script())?; + let vc_balance = vc_distribution.get(vc_participant_idx)?; + // lc_balance + vc_balance should be equal to values[i] + if lc_balance + vc_balance != values[i] { + return Ok(false); + } + } + Ok(true) + } } impl CKByteDistribution { @@ -356,6 +434,59 @@ impl Balances { ckbytes.append(&mut sudts); return ckbytes; } + + pub fn mk_unlocked_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + lc_to_vc_idx_map: &[u8; 2], + vc_balances: &Balances, + ) -> Vec<(CellOutput, bytes::Bytes)> { + let mut ckbytes = self.ckbytes().mk_unlocked_outputs( + &mut mk_lock_script, + indices.clone(), + lc_to_vc_idx_map, + &vc_balances.ckbytes().clone(), + ); + + let mut sudts = self.sudts().mk_unlocked_outputs( + mk_lock_script, + indices, + lc_to_vc_idx_map, + vc_balances.sudts(), + ); + ckbytes.append(&mut sudts); + return ckbytes; + } +} + +impl SubBalances { + /// Compares the sum of balances for each asset in SubBalances to the same in Balances(locked funds) + /// Returns true if the sum of balances for each asset in SubBalances is equal to the sum of balances for each asset in Balances + /// Returns false otherwise + pub fn equal_in_sum(&self, vc_balances: &Balances) -> Result { + let self_total_ckbytes = self.ckbytes().sum(); + let vc_ckbytes = vc_balances.ckbytes().sum(); + + if self_total_ckbytes != vc_ckbytes { + return Ok(false); + } + + if self.sudts().len() != vc_balances.sudts().len() { + return Ok(false); + } + + for locked_sudt in self.sudts().into_iter() { + for vc_sudt in vc_balances.sudts().into_iter() { + if locked_sudt.asset().as_slice() == vc_sudt.asset().as_slice() { + if locked_sudt.distribution().sum() != vc_sudt.distribution().sum() { + return Ok(false); + } + } + } + } + Ok(true) + } } #[cfg(feature = "std")] @@ -380,6 +511,32 @@ impl CKByteDistribution { acc }) } + + pub fn mk_unlocked_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + lc_to_vc_idx_map: &[u8; 2], + vc_balances: &CKByteDistribution, + ) -> Vec<(CellOutput, bytes::Bytes)> { + indices + .iter() + .fold(vec![], |mut acc: Vec<(CellOutput, bytes::Bytes)>, index| { + let cap = self.get(index.clone() as usize).expect("invalid index"); + let locked = vc_balances + .get(lc_to_vc_idx_map[*index as usize] as usize) + .expect("invalid index"); + let total_cap = cap + locked; + acc.push(( + CellOutput::new_builder() + .capacity(total_cap.pack()) + .lock(mk_lock_script(*index)) + .build(), + bytes::Bytes::new(), + )); + acc + }) + } } #[cfg(feature = "std")] @@ -429,6 +586,69 @@ impl SUDTAllocation { } return outputs; } + + pub fn mk_unlocked_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + lc_to_vc_idx_map: &[u8; 2], + vc_balances: SUDTAllocation, + ) -> Vec<(CellOutput, bytes::Bytes)> { + let mut outputs: Vec<(CellOutput, bytes::Bytes)> = Vec::new(); + for (i, balance) in self.into_iter().enumerate() { + let udt_type = balance.asset().type_script(); + let udt_type_opt = ScriptOpt::new_builder().set(Some(udt_type)).build(); + let cap: u64 = balance.asset().max_capacity().unpack(); + for f in indices.iter() { + if balance + .distribution() + .get(*f as usize) + .expect("invalid index") + == 0u128 + { + let bal = balance + .distribution() + .get(*f as usize) + .expect("invalid index"); + let vc_bal = vc_balances + .get(i as usize) + .expect("invalid index") + .distribution() + .get(lc_to_vc_idx_map[*f as usize] as usize) + .expect("invalid index"); + let total_bal = bal + vc_bal; + outputs.push(( + CellOutput::new_builder() + .capacity(cap.pack()) + .lock(mk_lock_script(*f)) + .build(), + bytes::Bytes::from(total_bal.to_le_bytes().to_vec()), + )); + } else { + let bal = balance + .distribution() + .get(*f as usize) + .expect("invalid index"); + let vc_bal = vc_balances + .get(i as usize) + .expect("invalid index") + .distribution() + .get(lc_to_vc_idx_map[*f as usize] as usize) + .expect("invalid index"); + let total_bal = bal + vc_bal; + outputs.push(( + CellOutput::new_builder() + .capacity(cap.pack()) + .lock(mk_lock_script(*f)) + .type_(udt_type_opt.clone()) + .build(), + bytes::Bytes::from(total_bal.to_le_bytes().to_vec()), + )); + } + } + } + return outputs; + } } impl ChannelParameters { diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/lib.rs similarity index 88% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs rename to payment-channel-ckb/devnet/contracts/crates/perun-common/src/lib.rs index 39d0017..9aef7c4 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod channels; pub mod error; pub mod helpers; #[allow(clippy::all)] diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/perun_types.rs similarity index 63% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs rename to payment-channel-ckb/devnet/contracts/crates/perun-common/src/perun_types.rs index 61fe220..bae2217 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/perun_types.rs @@ -1,14 +1,14 @@ -// Generated by Molecule 0.7.3 +// Generated by Molecule 0.8.0 + #![allow(unused_imports)] #[cfg(feature = "std")] use {ckb_types::packed::*, ckb_types::prelude::*}; #[cfg(not(feature = "std"))] -use {ckb_standalone_types::packed::*, ckb_standalone_types::prelude::*}; +use {ckb_gen_types::packed::*, ckb_gen_types::prelude::*}; use molecule::prelude::*; - #[derive(Clone)] pub struct SEC1EncodedPubKey(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for SEC1EncodedPubKey { @@ -34,14 +34,15 @@ impl ::core::fmt::Display for SEC1EncodedPubKey { } impl ::core::default::Default for SEC1EncodedPubKey { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - SEC1EncodedPubKey::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SEC1EncodedPubKey::new_unchecked(v) } } impl SEC1EncodedPubKey { + const DEFAULT_VALUE: [u8; 33] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]; pub const TOTAL_SIZE: usize = 33; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 33; @@ -361,6 +362,7 @@ impl<'r> molecule::prelude::Reader<'r> for SEC1EncodedPubKeyReader<'r> { Ok(()) } } +#[derive(Clone)] pub struct SEC1EncodedPubKeyBuilder(pub(crate) [Byte; 33]); impl ::core::fmt::Debug for SEC1EncodedPubKeyBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -596,6 +598,88 @@ impl molecule::prelude::Builder for SEC1EncodedPubKeyBuilder { SEC1EncodedPubKey::new_unchecked(inner.into()) } } +impl From<[Byte; 33usize]> for SEC1EncodedPubKey { + fn from(value: [Byte; 33usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for SEC1EncodedPubKey { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 33usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 33usize] { + #[track_caller] + fn from(value: SEC1EncodedPubKey) -> Self { + [ + value.nth0(), + value.nth1(), + value.nth2(), + value.nth3(), + value.nth4(), + value.nth5(), + value.nth6(), + value.nth7(), + value.nth8(), + value.nth9(), + value.nth10(), + value.nth11(), + value.nth12(), + value.nth13(), + value.nth14(), + value.nth15(), + value.nth16(), + value.nth17(), + value.nth18(), + value.nth19(), + value.nth20(), + value.nth21(), + value.nth22(), + value.nth23(), + value.nth24(), + value.nth25(), + value.nth26(), + value.nth27(), + value.nth28(), + value.nth29(), + value.nth30(), + value.nth31(), + value.nth32(), + ] + } +} +impl From<[u8; 33usize]> for SEC1EncodedPubKey { + fn from(value: [u8; 33usize]) -> Self { + SEC1EncodedPubKeyReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for SEC1EncodedPubKey { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 33usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 33usize] { + #[track_caller] + fn from(value: SEC1EncodedPubKey) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 33usize] { + #[track_caller] + fn from(value: SEC1EncodedPubKeyReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a SEC1EncodedPubKeyReader<'a>> for &'a [u8; 33usize] { + #[track_caller] + fn from(value: &'a SEC1EncodedPubKeyReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} #[derive(Clone)] pub struct CKByteDistribution(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for CKByteDistribution { @@ -622,11 +706,12 @@ impl ::core::fmt::Display for CKByteDistribution { } impl ::core::default::Default for CKByteDistribution { fn default() -> Self { - let v: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - CKByteDistribution::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + CKByteDistribution::new_unchecked(v) } } impl CKByteDistribution { + const DEFAULT_VALUE: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; pub const TOTAL_SIZE: usize = 16; pub const ITEM_SIZE: usize = 8; pub const ITEM_COUNT: usize = 2; @@ -721,6 +806,7 @@ impl<'r> molecule::prelude::Reader<'r> for CKByteDistributionReader<'r> { Ok(()) } } +#[derive(Clone)] pub struct CKByteDistributionBuilder(pub(crate) [Uint64; 2]); impl ::core::fmt::Debug for CKByteDistributionBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -767,6 +853,25 @@ impl molecule::prelude::Builder for CKByteDistributionBuilder { CKByteDistribution::new_unchecked(inner.into()) } } +impl From<[Uint64; 2usize]> for CKByteDistribution { + fn from(value: [Uint64; 2usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Uint64]> for CKByteDistribution { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Uint64]) -> Result { + Ok(Self::new_builder() + .set(<&[Uint64; 2usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Uint64; 2usize] { + #[track_caller] + fn from(value: CKByteDistribution) -> Self { + [value.nth0(), value.nth1()] + } +} #[derive(Clone)] pub struct SUDTDistribution(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for SUDTDistribution { @@ -793,14 +898,15 @@ impl ::core::fmt::Display for SUDTDistribution { } impl ::core::default::Default for SUDTDistribution { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]; - SUDTDistribution::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SUDTDistribution::new_unchecked(v) } } impl SUDTDistribution { + const DEFAULT_VALUE: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; pub const TOTAL_SIZE: usize = 32; pub const ITEM_SIZE: usize = 16; pub const ITEM_COUNT: usize = 2; @@ -895,6 +1001,7 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTDistributionReader<'r> { Ok(()) } } +#[derive(Clone)] pub struct SUDTDistributionBuilder(pub(crate) [Uint128; 2]); impl ::core::fmt::Debug for SUDTDistributionBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -941,6 +1048,25 @@ impl molecule::prelude::Builder for SUDTDistributionBuilder { SUDTDistribution::new_unchecked(inner.into()) } } +impl From<[Uint128; 2usize]> for SUDTDistribution { + fn from(value: [Uint128; 2usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Uint128]> for SUDTDistribution { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Uint128]) -> Result { + Ok(Self::new_builder() + .set(<&[Uint128; 2usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Uint128; 2usize] { + #[track_caller] + fn from(value: SUDTDistribution) -> Self { + [value.nth0(), value.nth1()] + } +} #[derive(Clone)] pub struct SUDTAllocation(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for SUDTAllocation { @@ -972,11 +1098,12 @@ impl ::core::fmt::Display for SUDTAllocation { } impl ::core::default::Default for SUDTAllocation { fn default() -> Self { - let v: Vec = vec![4, 0, 0, 0]; - SUDTAllocation::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SUDTAllocation::new_unchecked(v) } } impl SUDTAllocation { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -1163,7 +1290,7 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTAllocationReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct SUDTAllocationBuilder(pub(crate) Vec); impl SUDTAllocationBuilder { pub fn set(mut self, v: Vec) -> Self { @@ -1280,9 +1407,14 @@ impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for SUDTAllocationReaderIterato self.2 - self.1 } } +impl ::core::iter::FromIterator for SUDTAllocation { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} #[derive(Clone)] -pub struct SUDTAsset(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for SUDTAsset { +pub struct LockedBalances(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for LockedBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -1291,76 +1423,76 @@ impl ::core::fmt::LowerHex for SUDTAsset { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for SUDTAsset { +impl ::core::fmt::Debug for LockedBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for SUDTAsset { +impl ::core::fmt::Display for LockedBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "type_script", self.type_script())?; - write!(f, ", {}: {}", "max_capacity", self.max_capacity())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } } - write!(f, " }}") + write!(f, "]") } } -impl ::core::default::Default for SUDTAsset { +impl ::core::default::Default for LockedBalances { fn default() -> Self { - let v: Vec = vec![ - 73, 0, 0, 0, 12, 0, 0, 0, 65, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - SUDTAsset::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + LockedBalances::new_unchecked(v) } } -impl SUDTAsset { - pub const FIELD_COUNT: usize = 2; +impl LockedBalances { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } - pub fn field_count(&self) -> usize { + pub fn item_count(&self) -> usize { if self.total_size() == molecule::NUMBER_SIZE { 0 } else { (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 } } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT + pub fn len(&self) -> usize { + self.item_count() } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() + pub fn is_empty(&self) -> bool { + self.len() == 0 } - pub fn type_script(&self) -> Script { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Script::new_unchecked(self.0.slice(start..end)) + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } } - pub fn max_capacity(&self) -> Uint64 { + pub fn get_unchecked(&self, idx: usize) -> SubAlloc { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + SubAlloc::new_unchecked(self.0.slice(start..)) } else { - Uint64::new_unchecked(self.0.slice(start..)) + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + SubAlloc::new_unchecked(self.0.slice(start..end)) } } - pub fn as_reader<'r>(&'r self) -> SUDTAssetReader<'r> { - SUDTAssetReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> LockedBalancesReader<'r> { + LockedBalancesReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for SUDTAsset { - type Builder = SUDTAssetBuilder; - const NAME: &'static str = "SUDTAsset"; +impl molecule::prelude::Entity for LockedBalances { + type Builder = LockedBalancesBuilder; + const NAME: &'static str = "LockedBalances"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - SUDTAsset(data) + LockedBalances(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -1369,23 +1501,21 @@ impl molecule::prelude::Entity for SUDTAsset { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - SUDTAssetReader::from_slice(slice).map(|reader| reader.to_entity()) + LockedBalancesReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - SUDTAssetReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + LockedBalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .type_script(self.type_script()) - .max_capacity(self.max_capacity()) + Self::new_builder().extend(self.into_iter()) } } #[derive(Clone, Copy)] -pub struct SUDTAssetReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for SUDTAssetReader<'r> { +pub struct LockedBalancesReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for LockedBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -1394,66 +1524,69 @@ impl<'r> ::core::fmt::LowerHex for SUDTAssetReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for SUDTAssetReader<'r> { +impl<'r> ::core::fmt::Debug for LockedBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for SUDTAssetReader<'r> { +impl<'r> ::core::fmt::Display for LockedBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "type_script", self.type_script())?; - write!(f, ", {}: {}", "max_capacity", self.max_capacity())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } } - write!(f, " }}") + write!(f, "]") } } -impl<'r> SUDTAssetReader<'r> { - pub const FIELD_COUNT: usize = 2; +impl<'r> LockedBalancesReader<'r> { pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } - pub fn field_count(&self) -> usize { + pub fn item_count(&self) -> usize { if self.total_size() == molecule::NUMBER_SIZE { 0 } else { (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 } } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT + pub fn len(&self) -> usize { + self.item_count() } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() + pub fn is_empty(&self) -> bool { + self.len() == 0 } - pub fn type_script(&self) -> ScriptReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - ScriptReader::new_unchecked(&self.as_slice()[start..end]) + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } } - pub fn max_capacity(&self) -> Uint64Reader<'r> { + pub fn get_unchecked(&self, idx: usize) -> SubAllocReader<'r> { let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + SubAllocReader::new_unchecked(&self.as_slice()[start..]) } else { - Uint64Reader::new_unchecked(&self.as_slice()[start..]) + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + SubAllocReader::new_unchecked(&self.as_slice()[start..end]) } } } -impl<'r> molecule::prelude::Reader<'r> for SUDTAssetReader<'r> { - type Entity = SUDTAsset; - const NAME: &'static str = "SUDTAssetReader"; +impl<'r> molecule::prelude::Reader<'r> for LockedBalancesReader<'r> { + type Entity = LockedBalances; + const NAME: &'static str = "LockedBalancesReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - SUDTAssetReader(slice) + LockedBalancesReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -1468,11 +1601,16 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTAssetReader<'r> { if slice_len != total_size { return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { + if slice_len == molecule::NUMBER_SIZE { return Ok(()); } if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + return ve!( + Self, + TotalSizeNotMatch, + molecule::NUMBER_SIZE * 2, + slice_len + ); } let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { @@ -1481,12 +1619,6 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTAssetReader<'r> { if slice_len < offset_first { return ve!(Self, HeaderIsBroken, offset_first, slice_len); } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] .chunks_exact(molecule::NUMBER_SIZE) .map(|x| molecule::unpack_number(x) as usize) @@ -1495,98 +1627,176 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTAssetReader<'r> { if offsets.windows(2).any(|i| i[0] > i[1]) { return ve!(Self, OffsetsNotMatch); } - ScriptReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Uint64Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + SubAllocReader::verify(&slice[start..end], compatible)?; + } Ok(()) } } -#[derive(Debug, Default)] -pub struct SUDTAssetBuilder { - pub(crate) type_script: Script, - pub(crate) max_capacity: Uint64, -} -impl SUDTAssetBuilder { - pub const FIELD_COUNT: usize = 2; - pub fn type_script(mut self, v: Script) -> Self { - self.type_script = v; +#[derive(Clone, Debug, Default)] +pub struct LockedBalancesBuilder(pub(crate) Vec); +impl LockedBalancesBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; self } - pub fn max_capacity(mut self, v: Uint64) -> Self { - self.max_capacity = v; + pub fn push(mut self, v: SubAlloc) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } self } + pub fn replace(&mut self, index: usize, v: SubAlloc) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } } -impl molecule::prelude::Builder for SUDTAssetBuilder { - type Entity = SUDTAsset; - const NAME: &'static str = "SUDTAssetBuilder"; +impl molecule::prelude::Builder for LockedBalancesBuilder { + type Entity = LockedBalances; + const NAME: &'static str = "LockedBalancesBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.type_script.as_slice().len() - + self.max_capacity.as_slice().len() + molecule::NUMBER_SIZE * (self.0.len() + 1) + + self + .0 + .iter() + .map(|inner| inner.as_slice().len()) + .sum::() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.type_script.as_slice().len(); - offsets.push(total_size); - total_size += self.max_capacity.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number( + molecule::NUMBER_SIZE as molecule::Number, + ))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + ( + molecule::NUMBER_SIZE * (item_count + 1), + Vec::with_capacity(item_count), + ), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } } - writer.write_all(self.type_script.as_slice())?; - writer.write_all(self.max_capacity.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - SUDTAsset::new_unchecked(inner.into()) + LockedBalances::new_unchecked(inner.into()) } } -#[derive(Clone)] -pub struct SUDTBalances(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for SUDTBalances { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - if f.alternate() { - write!(f, "0x")?; +pub struct LockedBalancesIterator(LockedBalances, usize, usize); +impl ::core::iter::Iterator for LockedBalancesIterator { + type Item = SubAlloc; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) } - write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for SUDTBalances { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:#x})", Self::NAME, self) +impl ::core::iter::ExactSizeIterator for LockedBalancesIterator { + fn len(&self) -> usize { + self.2 - self.1 } } -impl ::core::fmt::Display for SUDTBalances { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "asset", self.asset())?; - write!(f, ", {}: {}", "distribution", self.distribution())?; - let extra_count = self.count_extra_fields(); +impl ::core::iter::IntoIterator for LockedBalances { + type Item = SubAlloc; + type IntoIter = LockedBalancesIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + LockedBalancesIterator(self, 0, len) + } +} +impl<'r> LockedBalancesReader<'r> { + pub fn iter<'t>(&'t self) -> LockedBalancesReaderIterator<'t, 'r> { + LockedBalancesReaderIterator(&self, 0, self.len()) + } +} +pub struct LockedBalancesReaderIterator<'t, 'r>(&'t LockedBalancesReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for LockedBalancesReaderIterator<'t, 'r> { + type Item = SubAllocReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for LockedBalancesReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::FromIterator for LockedBalances { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} +#[derive(Clone)] +pub struct SubAlloc(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SubAlloc { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for SubAlloc { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SubAlloc { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "id", self.id())?; + write!(f, ", {}: {}", "balances", self.balances())?; + let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; } write!(f, " }}") } } -impl ::core::default::Default for SUDTBalances { +impl ::core::default::Default for SubAlloc { fn default() -> Self { - let v: Vec = vec![ - 117, 0, 0, 0, 12, 0, 0, 0, 85, 0, 0, 0, 73, 0, 0, 0, 12, 0, 0, 0, 65, 0, 0, 0, 53, 0, - 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - ]; - SUDTBalances::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SubAlloc::new_unchecked(v) } } -impl SUDTBalances { +impl SubAlloc { + const DEFAULT_VALUE: [u8; 76] = [ + 76, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + ]; pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize @@ -1604,31 +1814,31 @@ impl SUDTBalances { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn asset(&self) -> SUDTAsset { + pub fn id(&self) -> Byte32 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - SUDTAsset::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(start..end)) } - pub fn distribution(&self) -> SUDTDistribution { + pub fn balances(&self) -> SubBalances { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; if self.has_extra_fields() { let end = molecule::unpack_number(&slice[12..]) as usize; - SUDTDistribution::new_unchecked(self.0.slice(start..end)) + SubBalances::new_unchecked(self.0.slice(start..end)) } else { - SUDTDistribution::new_unchecked(self.0.slice(start..)) + SubBalances::new_unchecked(self.0.slice(start..)) } } - pub fn as_reader<'r>(&'r self) -> SUDTBalancesReader<'r> { - SUDTBalancesReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> SubAllocReader<'r> { + SubAllocReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for SUDTBalances { - type Builder = SUDTBalancesBuilder; - const NAME: &'static str = "SUDTBalances"; +impl molecule::prelude::Entity for SubAlloc { + type Builder = SubAllocBuilder; + const NAME: &'static str = "SubAlloc"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - SUDTBalances(data) + SubAlloc(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -1637,23 +1847,21 @@ impl molecule::prelude::Entity for SUDTBalances { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - SUDTBalancesReader::from_slice(slice).map(|reader| reader.to_entity()) + SubAllocReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - SUDTBalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + SubAllocReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .asset(self.asset()) - .distribution(self.distribution()) + Self::new_builder().id(self.id()).balances(self.balances()) } } #[derive(Clone, Copy)] -pub struct SUDTBalancesReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for SUDTBalancesReader<'r> { +pub struct SubAllocReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SubAllocReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -1662,16 +1870,16 @@ impl<'r> ::core::fmt::LowerHex for SUDTBalancesReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for SUDTBalancesReader<'r> { +impl<'r> ::core::fmt::Debug for SubAllocReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for SUDTBalancesReader<'r> { +impl<'r> ::core::fmt::Display for SubAllocReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "asset", self.asset())?; - write!(f, ", {}: {}", "distribution", self.distribution())?; + write!(f, "{}: {}", "id", self.id())?; + write!(f, ", {}: {}", "balances", self.balances())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -1679,7 +1887,7 @@ impl<'r> ::core::fmt::Display for SUDTBalancesReader<'r> { write!(f, " }}") } } -impl<'r> SUDTBalancesReader<'r> { +impl<'r> SubAllocReader<'r> { pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize @@ -1697,31 +1905,31 @@ impl<'r> SUDTBalancesReader<'r> { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn asset(&self) -> SUDTAssetReader<'r> { + pub fn id(&self) -> Byte32Reader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - SUDTAssetReader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) } - pub fn distribution(&self) -> SUDTDistributionReader<'r> { + pub fn balances(&self) -> SubBalancesReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; if self.has_extra_fields() { let end = molecule::unpack_number(&slice[12..]) as usize; - SUDTDistributionReader::new_unchecked(&self.as_slice()[start..end]) + SubBalancesReader::new_unchecked(&self.as_slice()[start..end]) } else { - SUDTDistributionReader::new_unchecked(&self.as_slice()[start..]) + SubBalancesReader::new_unchecked(&self.as_slice()[start..]) } } } -impl<'r> molecule::prelude::Reader<'r> for SUDTBalancesReader<'r> { - type Entity = SUDTBalances; - const NAME: &'static str = "SUDTBalancesReader"; +impl<'r> molecule::prelude::Reader<'r> for SubAllocReader<'r> { + type Entity = SubAlloc; + const NAME: &'static str = "SubAllocReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - SUDTBalancesReader(slice) + SubAllocReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -1736,9 +1944,6 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTBalancesReader<'r> { if slice_len != total_size { return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } if slice_len < molecule::NUMBER_SIZE * 2 { return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); } @@ -1763,60 +1968,60 @@ impl<'r> molecule::prelude::Reader<'r> for SUDTBalancesReader<'r> { if offsets.windows(2).any(|i| i[0] > i[1]) { return ve!(Self, OffsetsNotMatch); } - SUDTAssetReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - SUDTDistributionReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + SubBalancesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct SUDTBalancesBuilder { - pub(crate) asset: SUDTAsset, - pub(crate) distribution: SUDTDistribution, +#[derive(Clone, Debug, Default)] +pub struct SubAllocBuilder { + pub(crate) id: Byte32, + pub(crate) balances: SubBalances, } -impl SUDTBalancesBuilder { +impl SubAllocBuilder { pub const FIELD_COUNT: usize = 2; - pub fn asset(mut self, v: SUDTAsset) -> Self { - self.asset = v; + pub fn id(mut self, v: Byte32) -> Self { + self.id = v; self } - pub fn distribution(mut self, v: SUDTDistribution) -> Self { - self.distribution = v; + pub fn balances(mut self, v: SubBalances) -> Self { + self.balances = v; self } } -impl molecule::prelude::Builder for SUDTBalancesBuilder { - type Entity = SUDTBalances; - const NAME: &'static str = "SUDTBalancesBuilder"; +impl molecule::prelude::Builder for SubAllocBuilder { + type Entity = SubAlloc; + const NAME: &'static str = "SubAllocBuilder"; fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.asset.as_slice().len() - + self.distribution.as_slice().len() + + self.id.as_slice().len() + + self.balances.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); offsets.push(total_size); - total_size += self.asset.as_slice().len(); + total_size += self.id.as_slice().len(); offsets.push(total_size); - total_size += self.distribution.as_slice().len(); + total_size += self.balances.as_slice().len(); writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; for offset in offsets.into_iter() { writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } - writer.write_all(self.asset.as_slice())?; - writer.write_all(self.distribution.as_slice())?; + writer.write_all(self.id.as_slice())?; + writer.write_all(self.balances.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - SUDTBalances::new_unchecked(inner.into()) + SubAlloc::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Balances(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Balances { +pub struct SubBalances(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SubBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -1825,12 +2030,12 @@ impl ::core::fmt::LowerHex for Balances { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Balances { +impl ::core::fmt::Debug for SubBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Balances { +impl ::core::fmt::Display for SubBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "ckbytes", self.ckbytes())?; @@ -1842,16 +2047,17 @@ impl ::core::fmt::Display for Balances { write!(f, " }}") } } -impl ::core::default::Default for Balances { +impl ::core::default::Default for SubBalances { fn default() -> Self { - let v: Vec = vec![ - 32, 0, 0, 0, 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, - ]; - Balances::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SubBalances::new_unchecked(v) } } -impl Balances { +impl SubBalances { + const DEFAULT_VALUE: [u8; 32] = [ + 32, 0, 0, 0, 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + 0, 0, 0, + ]; pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize @@ -1885,15 +2091,15 @@ impl Balances { SUDTAllocation::new_unchecked(self.0.slice(start..)) } } - pub fn as_reader<'r>(&'r self) -> BalancesReader<'r> { - BalancesReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> SubBalancesReader<'r> { + SubBalancesReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Balances { - type Builder = BalancesBuilder; - const NAME: &'static str = "Balances"; +impl molecule::prelude::Entity for SubBalances { + type Builder = SubBalancesBuilder; + const NAME: &'static str = "SubBalances"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Balances(data) + SubBalances(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -1902,10 +2108,10 @@ impl molecule::prelude::Entity for Balances { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BalancesReader::from_slice(slice).map(|reader| reader.to_entity()) + SubBalancesReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + SubBalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() @@ -1917,8 +2123,8 @@ impl molecule::prelude::Entity for Balances { } } #[derive(Clone, Copy)] -pub struct BalancesReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for BalancesReader<'r> { +pub struct SubBalancesReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SubBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -1927,12 +2133,12 @@ impl<'r> ::core::fmt::LowerHex for BalancesReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for BalancesReader<'r> { +impl<'r> ::core::fmt::Debug for SubBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for BalancesReader<'r> { +impl<'r> ::core::fmt::Display for SubBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; write!(f, "{}: {}", "ckbytes", self.ckbytes())?; @@ -1944,7 +2150,7 @@ impl<'r> ::core::fmt::Display for BalancesReader<'r> { write!(f, " }}") } } -impl<'r> BalancesReader<'r> { +impl<'r> SubBalancesReader<'r> { pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize @@ -1979,14 +2185,14 @@ impl<'r> BalancesReader<'r> { } } } -impl<'r> molecule::prelude::Reader<'r> for BalancesReader<'r> { - type Entity = Balances; - const NAME: &'static str = "BalancesReader"; +impl<'r> molecule::prelude::Reader<'r> for SubBalancesReader<'r> { + type Entity = SubBalances; + const NAME: &'static str = "SubBalancesReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - BalancesReader(slice) + SubBalancesReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -2001,9 +2207,6 @@ impl<'r> molecule::prelude::Reader<'r> for BalancesReader<'r> { if slice_len != total_size { return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } if slice_len < molecule::NUMBER_SIZE * 2 { return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); } @@ -2033,12 +2236,12 @@ impl<'r> molecule::prelude::Reader<'r> for BalancesReader<'r> { Ok(()) } } -#[derive(Debug, Default)] -pub struct BalancesBuilder { +#[derive(Clone, Debug, Default)] +pub struct SubBalancesBuilder { pub(crate) ckbytes: CKByteDistribution, pub(crate) sudts: SUDTAllocation, } -impl BalancesBuilder { +impl SubBalancesBuilder { pub const FIELD_COUNT: usize = 2; pub fn ckbytes(mut self, v: CKByteDistribution) -> Self { self.ckbytes = v; @@ -2049,9 +2252,9 @@ impl BalancesBuilder { self } } -impl molecule::prelude::Builder for BalancesBuilder { - type Entity = Balances; - const NAME: &'static str = "BalancesBuilder"; +impl molecule::prelude::Builder for SubBalancesBuilder { + type Entity = SubBalances; + const NAME: &'static str = "SubBalancesBuilder"; fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.ckbytes.as_slice().len() @@ -2076,12 +2279,12 @@ impl molecule::prelude::Builder for BalancesBuilder { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Balances::new_unchecked(inner.into()) + SubBalances::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct True(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for True { +pub struct SUDTAsset(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SUDTAsset { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2090,43 +2293,77 @@ impl ::core::fmt::LowerHex for True { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for True { +impl ::core::fmt::Debug for SUDTAsset { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for True { +impl ::core::fmt::Display for SUDTAsset { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "type_script", self.type_script())?; + write!(f, ", {}: {}", "max_capacity", self.max_capacity())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl ::core::default::Default for True { +impl ::core::default::Default for SUDTAsset { fn default() -> Self { - let v: Vec = vec![0]; - True::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SUDTAsset::new_unchecked(v) } } -impl True { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> Byte { - Byte::new_unchecked(self.0.slice(0..1)) +impl SUDTAsset { + const DEFAULT_VALUE: [u8; 73] = [ + 73, 0, 0, 0, 12, 0, 0, 0, 65, 0, 0, 0, 53, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> molecule::bytes::Bytes { - self.as_bytes() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } - pub fn as_reader<'r>(&'r self) -> TrueReader<'r> { - TrueReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn type_script(&self) -> Script { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Script::new_unchecked(self.0.slice(start..end)) + } + pub fn max_capacity(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } else { + Uint64::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> SUDTAssetReader<'r> { + SUDTAssetReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for True { - type Builder = TrueBuilder; - const NAME: &'static str = "True"; +impl molecule::prelude::Entity for SUDTAsset { + type Builder = SUDTAssetBuilder; + const NAME: &'static str = "SUDTAsset"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - True(data) + SUDTAsset(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -2135,21 +2372,23 @@ impl molecule::prelude::Entity for True { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - TrueReader::from_slice(slice).map(|reader| reader.to_entity()) + SUDTAssetReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - TrueReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + SUDTAssetReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set([self.nth0()]) + Self::new_builder() + .type_script(self.type_script()) + .max_capacity(self.max_capacity()) } } #[derive(Clone, Copy)] -pub struct TrueReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for TrueReader<'r> { +pub struct SUDTAssetReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SUDTAssetReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2158,94 +2397,158 @@ impl<'r> ::core::fmt::LowerHex for TrueReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for TrueReader<'r> { +impl<'r> ::core::fmt::Debug for SUDTAssetReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for TrueReader<'r> { +impl<'r> ::core::fmt::Display for SUDTAssetReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "type_script", self.type_script())?; + write!(f, ", {}: {}", "max_capacity", self.max_capacity())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl<'r> TrueReader<'r> { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> ByteReader<'r> { - ByteReader::new_unchecked(&self.as_slice()[0..1]) +impl<'r> SUDTAssetReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> &'r [u8] { - self.as_slice() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } -} -impl<'r> molecule::prelude::Reader<'r> for TrueReader<'r> { - type Entity = True; - const NAME: &'static str = "TrueReader"; + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn type_script(&self) -> ScriptReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ScriptReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn max_capacity(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } else { + Uint64Reader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SUDTAssetReader<'r> { + type Entity = SUDTAsset; + const NAME: &'static str = "SUDTAssetReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - TrueReader(slice) + SUDTAssetReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len != Self::TOTAL_SIZE { - return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ScriptReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint64Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } -pub struct TrueBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for TrueBuilder { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:?})", Self::NAME, &self.0[..]) - } -} -impl ::core::default::Default for TrueBuilder { - fn default() -> Self { - TrueBuilder([Byte::default()]) - } +#[derive(Clone, Debug, Default)] +pub struct SUDTAssetBuilder { + pub(crate) type_script: Script, + pub(crate) max_capacity: Uint64, } -impl TrueBuilder { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn set(mut self, v: [Byte; 1]) -> Self { - self.0 = v; +impl SUDTAssetBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn type_script(mut self, v: Script) -> Self { + self.type_script = v; self } - pub fn nth0(mut self, v: Byte) -> Self { - self.0[0] = v; + pub fn max_capacity(mut self, v: Uint64) -> Self { + self.max_capacity = v; self } } -impl molecule::prelude::Builder for TrueBuilder { - type Entity = True; - const NAME: &'static str = "TrueBuilder"; +impl molecule::prelude::Builder for SUDTAssetBuilder { + type Entity = SUDTAsset; + const NAME: &'static str = "SUDTAssetBuilder"; fn expected_length(&self) -> usize { - Self::TOTAL_SIZE + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.type_script.as_slice().len() + + self.max_capacity.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(self.0[0].as_slice())?; + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.type_script.as_slice().len(); + offsets.push(total_size); + total_size += self.max_capacity.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.type_script.as_slice())?; + writer.write_all(self.max_capacity.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - True::new_unchecked(inner.into()) + SUDTAsset::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct False(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for False { +pub struct SUDTBalances(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SUDTBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2254,43 +2557,78 @@ impl ::core::fmt::LowerHex for False { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for False { +impl ::core::fmt::Debug for SUDTBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for False { +impl ::core::fmt::Display for SUDTBalances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "asset", self.asset())?; + write!(f, ", {}: {}", "distribution", self.distribution())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl ::core::default::Default for False { +impl ::core::default::Default for SUDTBalances { fn default() -> Self { - let v: Vec = vec![0]; - False::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + SUDTBalances::new_unchecked(v) } } -impl False { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> Byte { - Byte::new_unchecked(self.0.slice(0..1)) +impl SUDTBalances { + const DEFAULT_VALUE: [u8; 117] = [ + 117, 0, 0, 0, 12, 0, 0, 0, 85, 0, 0, 0, 73, 0, 0, 0, 12, 0, 0, 0, 65, 0, 0, 0, 53, 0, 0, 0, + 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> molecule::bytes::Bytes { - self.as_bytes() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } - pub fn as_reader<'r>(&'r self) -> FalseReader<'r> { - FalseReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn asset(&self) -> SUDTAsset { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + SUDTAsset::new_unchecked(self.0.slice(start..end)) + } + pub fn distribution(&self) -> SUDTDistribution { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + SUDTDistribution::new_unchecked(self.0.slice(start..end)) + } else { + SUDTDistribution::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> SUDTBalancesReader<'r> { + SUDTBalancesReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for False { - type Builder = FalseBuilder; - const NAME: &'static str = "False"; +impl molecule::prelude::Entity for SUDTBalances { + type Builder = SUDTBalancesBuilder; + const NAME: &'static str = "SUDTBalances"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - False(data) + SUDTBalances(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -2299,21 +2637,23 @@ impl molecule::prelude::Entity for False { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - FalseReader::from_slice(slice).map(|reader| reader.to_entity()) + SUDTBalancesReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - FalseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + SUDTBalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set([self.nth0()]) + Self::new_builder() + .asset(self.asset()) + .distribution(self.distribution()) } } #[derive(Clone, Copy)] -pub struct FalseReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for FalseReader<'r> { +pub struct SUDTBalancesReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SUDTBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2322,94 +2662,158 @@ impl<'r> ::core::fmt::LowerHex for FalseReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for FalseReader<'r> { +impl<'r> ::core::fmt::Debug for SUDTBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for FalseReader<'r> { +impl<'r> ::core::fmt::Display for SUDTBalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "asset", self.asset())?; + write!(f, ", {}: {}", "distribution", self.distribution())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl<'r> FalseReader<'r> { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> ByteReader<'r> { - ByteReader::new_unchecked(&self.as_slice()[0..1]) +impl<'r> SUDTBalancesReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> &'r [u8] { - self.as_slice() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } -} -impl<'r> molecule::prelude::Reader<'r> for FalseReader<'r> { - type Entity = False; - const NAME: &'static str = "FalseReader"; - fn to_entity(&self) -> Self::Entity { - Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT } - fn new_unchecked(slice: &'r [u8]) -> Self { - FalseReader(slice) + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() } - fn as_slice(&self) -> &'r [u8] { - self.0 + pub fn asset(&self) -> SUDTAssetReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + SUDTAssetReader::new_unchecked(&self.as_slice()[start..end]) } - fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { - use molecule::verification_error as ve; - let slice_len = slice.len(); - if slice_len != Self::TOTAL_SIZE { - return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + pub fn distribution(&self) -> SUDTDistributionReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + SUDTDistributionReader::new_unchecked(&self.as_slice()[start..end]) + } else { + SUDTDistributionReader::new_unchecked(&self.as_slice()[start..]) } - Ok(()) } } -pub struct FalseBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for FalseBuilder { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:?})", Self::NAME, &self.0[..]) +impl<'r> molecule::prelude::Reader<'r> for SUDTBalancesReader<'r> { + type Entity = SUDTBalances; + const NAME: &'static str = "SUDTBalancesReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } -} -impl ::core::default::Default for FalseBuilder { - fn default() -> Self { - FalseBuilder([Byte::default()]) + fn new_unchecked(slice: &'r [u8]) -> Self { + SUDTBalancesReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + SUDTAssetReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + SUDTDistributionReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) } } -impl FalseBuilder { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn set(mut self, v: [Byte; 1]) -> Self { - self.0 = v; +#[derive(Clone, Debug, Default)] +pub struct SUDTBalancesBuilder { + pub(crate) asset: SUDTAsset, + pub(crate) distribution: SUDTDistribution, +} +impl SUDTBalancesBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn asset(mut self, v: SUDTAsset) -> Self { + self.asset = v; self } - pub fn nth0(mut self, v: Byte) -> Self { - self.0[0] = v; + pub fn distribution(mut self, v: SUDTDistribution) -> Self { + self.distribution = v; self } } -impl molecule::prelude::Builder for FalseBuilder { - type Entity = False; - const NAME: &'static str = "FalseBuilder"; +impl molecule::prelude::Builder for SUDTBalancesBuilder { + type Entity = SUDTBalances; + const NAME: &'static str = "SUDTBalancesBuilder"; fn expected_length(&self) -> usize { - Self::TOTAL_SIZE + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.asset.as_slice().len() + + self.distribution.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(self.0[0].as_slice())?; + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.asset.as_slice().len(); + offsets.push(total_size); + total_size += self.distribution.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.asset.as_slice())?; + writer.write_all(self.distribution.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - False::new_unchecked(inner.into()) + SUDTBalances::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Bool(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Bool { +pub struct Balances(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Balances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2418,46 +2822,83 @@ impl ::core::fmt::LowerHex for Bool { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Bool { +impl ::core::fmt::Debug for Balances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Bool { +impl ::core::fmt::Display for Balances { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}(", Self::NAME)?; - self.to_enum().display_inner(f)?; - write!(f, ")") + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "ckbytes", self.ckbytes())?; + write!(f, ", {}: {}", "sudts", self.sudts())?; + write!(f, ", {}: {}", "locked", self.locked())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl ::core::default::Default for Bool { +impl ::core::default::Default for Balances { fn default() -> Self { - let v: Vec = vec![0, 0, 0, 0, 0]; - Bool::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Balances::new_unchecked(v) } } -impl Bool { - pub const ITEMS_COUNT: usize = 2; - pub fn item_id(&self) -> molecule::Number { - molecule::unpack_number(self.as_slice()) +impl Balances { + const DEFAULT_VALUE: [u8; 40] = [ + 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn to_enum(&self) -> BoolUnion { - let inner = self.0.slice(molecule::NUMBER_SIZE..); - match self.item_id() { - 0 => True::new_unchecked(inner).into(), - 1 => False::new_unchecked(inner).into(), - _ => panic!("{}: invalid data", Self::NAME), + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 } } - pub fn as_reader<'r>(&'r self) -> BoolReader<'r> { - BoolReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn ckbytes(&self) -> CKByteDistribution { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + CKByteDistribution::new_unchecked(self.0.slice(start..end)) + } + pub fn sudts(&self) -> SUDTAllocation { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + SUDTAllocation::new_unchecked(self.0.slice(start..end)) + } + pub fn locked(&self) -> LockedBalances { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + LockedBalances::new_unchecked(self.0.slice(start..end)) + } else { + LockedBalances::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> BalancesReader<'r> { + BalancesReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Bool { - type Builder = BoolBuilder; - const NAME: &'static str = "Bool"; +impl molecule::prelude::Entity for Balances { + type Builder = BalancesBuilder; + const NAME: &'static str = "Balances"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Bool(data) + Balances(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -2466,21 +2907,24 @@ impl molecule::prelude::Entity for Bool { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BoolReader::from_slice(slice).map(|reader| reader.to_entity()) + BalancesReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BoolReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + BalancesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set(self.to_enum()) + Self::new_builder() + .ckbytes(self.ckbytes()) + .sudts(self.sudts()) + .locked(self.locked()) } } #[derive(Clone, Copy)] -pub struct BoolReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for BoolReader<'r> { +pub struct BalancesReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2489,221 +2933,175 @@ impl<'r> ::core::fmt::LowerHex for BoolReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for BoolReader<'r> { +impl<'r> ::core::fmt::Debug for BalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for BoolReader<'r> { +impl<'r> ::core::fmt::Display for BalancesReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}(", Self::NAME)?; - self.to_enum().display_inner(f)?; - write!(f, ")") + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "ckbytes", self.ckbytes())?; + write!(f, ", {}: {}", "sudts", self.sudts())?; + write!(f, ", {}: {}", "locked", self.locked())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl<'r> BoolReader<'r> { - pub const ITEMS_COUNT: usize = 2; - pub fn item_id(&self) -> molecule::Number { - molecule::unpack_number(self.as_slice()) +impl<'r> BalancesReader<'r> { + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn to_enum(&self) -> BoolUnionReader<'r> { - let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; - match self.item_id() { - 0 => TrueReader::new_unchecked(inner).into(), - 1 => FalseReader::new_unchecked(inner).into(), - _ => panic!("{}: invalid data", Self::NAME), + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 } } -} -impl<'r> molecule::prelude::Reader<'r> for BoolReader<'r> { - type Entity = Bool; - const NAME: &'static str = "BoolReader"; - fn to_entity(&self) -> Self::Entity { - Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT } - fn new_unchecked(slice: &'r [u8]) -> Self { - BoolReader(slice) + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() } - fn as_slice(&self) -> &'r [u8] { - self.0 + pub fn ckbytes(&self) -> CKByteDistributionReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + CKByteDistributionReader::new_unchecked(&self.as_slice()[start..end]) } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { - use molecule::verification_error as ve; - let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let item_id = molecule::unpack_number(slice); - let inner_slice = &slice[molecule::NUMBER_SIZE..]; - match item_id { - 0 => TrueReader::verify(inner_slice, compatible), - 1 => FalseReader::verify(inner_slice, compatible), - _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), - }?; - Ok(()) + pub fn sudts(&self) -> SUDTAllocationReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + SUDTAllocationReader::new_unchecked(&self.as_slice()[start..end]) } -} -#[derive(Debug, Default)] -pub struct BoolBuilder(pub(crate) BoolUnion); -impl BoolBuilder { - pub const ITEMS_COUNT: usize = 2; - pub fn set(mut self, v: I) -> Self - where - I: ::core::convert::Into, - { - self.0 = v.into(); - self + pub fn locked(&self) -> LockedBalancesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + LockedBalancesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + LockedBalancesReader::new_unchecked(&self.as_slice()[start..]) + } } } -impl molecule::prelude::Builder for BoolBuilder { - type Entity = Bool; - const NAME: &'static str = "BoolBuilder"; - fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE + self.0.as_slice().len() - } - fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(&molecule::pack_number(self.0.item_id()))?; - writer.write_all(self.0.as_slice()) +impl<'r> molecule::prelude::Reader<'r> for BalancesReader<'r> { + type Entity = Balances; + const NAME: &'static str = "BalancesReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } - fn build(&self) -> Self::Entity { - let mut inner = Vec::with_capacity(self.expected_length()); - self.write(&mut inner) - .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Bool::new_unchecked(inner.into()) + fn new_unchecked(slice: &'r [u8]) -> Self { + BalancesReader(slice) } -} -#[derive(Debug, Clone)] -pub enum BoolUnion { - True(True), - False(False), -} -#[derive(Debug, Clone, Copy)] -pub enum BoolUnionReader<'r> { - True(TrueReader<'r>), - False(FalseReader<'r>), -} -impl ::core::default::Default for BoolUnion { - fn default() -> Self { - BoolUnion::True(::core::default::Default::default()) + fn as_slice(&self) -> &'r [u8] { + self.0 } -} -impl ::core::fmt::Display for BoolUnion { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - BoolUnion::True(ref item) => { - write!(f, "{}::{}({})", Self::NAME, True::NAME, item) - } - BoolUnion::False(ref item) => { - write!(f, "{}::{}({})", Self::NAME, False::NAME, item) - } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); } - } -} -impl<'r> ::core::fmt::Display for BoolUnionReader<'r> { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - BoolUnionReader::True(ref item) => { - write!(f, "{}::{}({})", Self::NAME, True::NAME, item) - } - BoolUnionReader::False(ref item) => { - write!(f, "{}::{}({})", Self::NAME, False::NAME, item) - } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - } -} -impl BoolUnion { - pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - BoolUnion::True(ref item) => write!(f, "{}", item), - BoolUnion::False(ref item) => write!(f, "{}", item), + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); } - } -} -impl<'r> BoolUnionReader<'r> { - pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - BoolUnionReader::True(ref item) => write!(f, "{}", item), - BoolUnionReader::False(ref item) => write!(f, "{}", item), + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); } - } -} -impl ::core::convert::From for BoolUnion { - fn from(item: True) -> Self { - BoolUnion::True(item) - } -} -impl ::core::convert::From for BoolUnion { - fn from(item: False) -> Self { - BoolUnion::False(item) - } -} -impl<'r> ::core::convert::From> for BoolUnionReader<'r> { - fn from(item: TrueReader<'r>) -> Self { - BoolUnionReader::True(item) - } -} -impl<'r> ::core::convert::From> for BoolUnionReader<'r> { - fn from(item: FalseReader<'r>) -> Self { - BoolUnionReader::False(item) - } -} -impl BoolUnion { - pub const NAME: &'static str = "BoolUnion"; - pub fn as_bytes(&self) -> molecule::bytes::Bytes { - match self { - BoolUnion::True(item) => item.as_bytes(), - BoolUnion::False(item) => item.as_bytes(), + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); } - } - pub fn as_slice(&self) -> &[u8] { - match self { - BoolUnion::True(item) => item.as_slice(), - BoolUnion::False(item) => item.as_slice(), + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); } + CKByteDistributionReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + SUDTAllocationReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + LockedBalancesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Ok(()) } - pub fn item_id(&self) -> molecule::Number { - match self { - BoolUnion::True(_) => 0, - BoolUnion::False(_) => 1, - } +} +#[derive(Clone, Debug, Default)] +pub struct BalancesBuilder { + pub(crate) ckbytes: CKByteDistribution, + pub(crate) sudts: SUDTAllocation, + pub(crate) locked: LockedBalances, +} +impl BalancesBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn ckbytes(mut self, v: CKByteDistribution) -> Self { + self.ckbytes = v; + self } - pub fn item_name(&self) -> &str { - match self { - BoolUnion::True(_) => "True", - BoolUnion::False(_) => "False", - } + pub fn sudts(mut self, v: SUDTAllocation) -> Self { + self.sudts = v; + self } - pub fn as_reader<'r>(&'r self) -> BoolUnionReader<'r> { - match self { - BoolUnion::True(item) => item.as_reader().into(), - BoolUnion::False(item) => item.as_reader().into(), - } + pub fn locked(mut self, v: LockedBalances) -> Self { + self.locked = v; + self } } -impl<'r> BoolUnionReader<'r> { - pub const NAME: &'r str = "BoolUnionReader"; - pub fn as_slice(&self) -> &'r [u8] { - match self { - BoolUnionReader::True(item) => item.as_slice(), - BoolUnionReader::False(item) => item.as_slice(), - } +impl molecule::prelude::Builder for BalancesBuilder { + type Entity = Balances; + const NAME: &'static str = "BalancesBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.ckbytes.as_slice().len() + + self.sudts.as_slice().len() + + self.locked.as_slice().len() } - pub fn item_id(&self) -> molecule::Number { - match self { - BoolUnionReader::True(_) => 0, - BoolUnionReader::False(_) => 1, + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.ckbytes.as_slice().len(); + offsets.push(total_size); + total_size += self.sudts.as_slice().len(); + offsets.push(total_size); + total_size += self.locked.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } + writer.write_all(self.ckbytes.as_slice())?; + writer.write_all(self.sudts.as_slice())?; + writer.write_all(self.locked.as_slice())?; + Ok(()) } - pub fn item_name(&self) -> &str { - match self { - BoolUnionReader::True(_) => "True", - BoolUnionReader::False(_) => "False", - } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Balances::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct A(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for A { +pub struct True(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for True { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2712,25 +3110,26 @@ impl ::core::fmt::LowerHex for A { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for A { +impl ::core::fmt::Debug for True { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for A { +impl ::core::fmt::Display for True { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl ::core::default::Default for A { +impl ::core::default::Default for True { fn default() -> Self { - let v: Vec = vec![0]; - A::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + True::new_unchecked(v) } } -impl A { +impl True { + const DEFAULT_VALUE: [u8; 1] = [0]; pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -2740,15 +3139,15 @@ impl A { pub fn raw_data(&self) -> molecule::bytes::Bytes { self.as_bytes() } - pub fn as_reader<'r>(&'r self) -> AReader<'r> { - AReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> TrueReader<'r> { + TrueReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for A { - type Builder = ABuilder; - const NAME: &'static str = "A"; - fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - A(data) +impl molecule::prelude::Entity for True { + type Builder = TrueBuilder; + const NAME: &'static str = "True"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + True(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -2757,10 +3156,10 @@ impl molecule::prelude::Entity for A { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AReader::from_slice(slice).map(|reader| reader.to_entity()) + TrueReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + TrueReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() @@ -2770,8 +3169,8 @@ impl molecule::prelude::Entity for A { } } #[derive(Clone, Copy)] -pub struct AReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for AReader<'r> { +pub struct TrueReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for TrueReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2780,19 +3179,19 @@ impl<'r> ::core::fmt::LowerHex for AReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for AReader<'r> { +impl<'r> ::core::fmt::Debug for TrueReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for AReader<'r> { +impl<'r> ::core::fmt::Display for TrueReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> AReader<'r> { +impl<'r> TrueReader<'r> { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -2803,14 +3202,14 @@ impl<'r> AReader<'r> { self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for AReader<'r> { - type Entity = A; - const NAME: &'static str = "AReader"; +impl<'r> molecule::prelude::Reader<'r> for TrueReader<'r> { + type Entity = True; + const NAME: &'static str = "TrueReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - AReader(slice) + TrueReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -2824,18 +3223,19 @@ impl<'r> molecule::prelude::Reader<'r> for AReader<'r> { Ok(()) } } -pub struct ABuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for ABuilder { +#[derive(Clone)] +pub struct TrueBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for TrueBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:?})", Self::NAME, &self.0[..]) } } -impl ::core::default::Default for ABuilder { +impl ::core::default::Default for TrueBuilder { fn default() -> Self { - ABuilder([Byte::default()]) + TrueBuilder([Byte::default()]) } } -impl ABuilder { +impl TrueBuilder { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -2848,9 +3248,9 @@ impl ABuilder { self } } -impl molecule::prelude::Builder for ABuilder { - type Entity = A; - const NAME: &'static str = "ABuilder"; +impl molecule::prelude::Builder for TrueBuilder { + type Entity = True; + const NAME: &'static str = "TrueBuilder"; fn expected_length(&self) -> usize { Self::TOTAL_SIZE } @@ -2862,12 +3262,60 @@ impl molecule::prelude::Builder for ABuilder { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - A::new_unchecked(inner.into()) + True::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for True { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for True { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: True) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for True { + fn from(value: [u8; 1usize]) -> Self { + TrueReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for True { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: True) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: TrueReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a TrueReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a TrueReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct B(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for B { +pub struct False(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for False { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2876,25 +3324,26 @@ impl ::core::fmt::LowerHex for B { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for B { +impl ::core::fmt::Debug for False { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for B { +impl ::core::fmt::Display for False { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl ::core::default::Default for B { +impl ::core::default::Default for False { fn default() -> Self { - let v: Vec = vec![0]; - B::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + False::new_unchecked(v) } } -impl B { +impl False { + const DEFAULT_VALUE: [u8; 1] = [0]; pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -2904,15 +3353,15 @@ impl B { pub fn raw_data(&self) -> molecule::bytes::Bytes { self.as_bytes() } - pub fn as_reader<'r>(&'r self) -> BReader<'r> { - BReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> FalseReader<'r> { + FalseReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for B { - type Builder = BBuilder; - const NAME: &'static str = "B"; +impl molecule::prelude::Entity for False { + type Builder = FalseBuilder; + const NAME: &'static str = "False"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - B(data) + False(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -2921,10 +3370,10 @@ impl molecule::prelude::Entity for B { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BReader::from_slice(slice).map(|reader| reader.to_entity()) + FalseReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - BReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + FalseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() @@ -2934,8 +3383,8 @@ impl molecule::prelude::Entity for B { } } #[derive(Clone, Copy)] -pub struct BReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for BReader<'r> { +pub struct FalseReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for FalseReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -2944,19 +3393,19 @@ impl<'r> ::core::fmt::LowerHex for BReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for BReader<'r> { +impl<'r> ::core::fmt::Debug for FalseReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for BReader<'r> { +impl<'r> ::core::fmt::Display for FalseReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> BReader<'r> { +impl<'r> FalseReader<'r> { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -2967,14 +3416,14 @@ impl<'r> BReader<'r> { self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for BReader<'r> { - type Entity = B; - const NAME: &'static str = "BReader"; +impl<'r> molecule::prelude::Reader<'r> for FalseReader<'r> { + type Entity = False; + const NAME: &'static str = "FalseReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - BReader(slice) + FalseReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -2988,18 +3437,19 @@ impl<'r> molecule::prelude::Reader<'r> for BReader<'r> { Ok(()) } } -pub struct BBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for BBuilder { +#[derive(Clone)] +pub struct FalseBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for FalseBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:?})", Self::NAME, &self.0[..]) } } -impl ::core::default::Default for BBuilder { +impl ::core::default::Default for FalseBuilder { fn default() -> Self { - BBuilder([Byte::default()]) + FalseBuilder([Byte::default()]) } } -impl BBuilder { +impl FalseBuilder { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -3012,9 +3462,9 @@ impl BBuilder { self } } -impl molecule::prelude::Builder for BBuilder { - type Entity = B; - const NAME: &'static str = "BBuilder"; +impl molecule::prelude::Builder for FalseBuilder { + type Entity = False; + const NAME: &'static str = "FalseBuilder"; fn expected_length(&self) -> usize { Self::TOTAL_SIZE } @@ -3026,12 +3476,60 @@ impl molecule::prelude::Builder for BBuilder { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - B::new_unchecked(inner.into()) + False::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for False { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for False { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: False) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for False { + fn from(value: [u8; 1usize]) -> Self { + FalseReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for False { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: False) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: FalseReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a FalseReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a FalseReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct App(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for App { +pub struct Bool(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Bool { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -3040,49 +3538,47 @@ impl ::core::fmt::LowerHex for App { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for App { +impl ::core::fmt::Debug for Bool { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for App { +impl ::core::fmt::Display for Bool { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - if let Some(v) = self.to_opt() { - write!(f, "{}(Some({}))", Self::NAME, v) - } else { - write!(f, "{}(None)", Self::NAME) - } + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") } } -impl ::core::default::Default for App { +impl ::core::default::Default for Bool { fn default() -> Self { - let v: Vec = vec![]; - App::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Bool::new_unchecked(v) } } -impl App { - pub fn is_none(&self) -> bool { - self.0.is_empty() - } - pub fn is_some(&self) -> bool { - !self.0.is_empty() +impl Bool { + const DEFAULT_VALUE: [u8; 5] = [0, 0, 0, 0, 0]; + pub const ITEMS_COUNT: usize = 2; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) } - pub fn to_opt(&self) -> Option { - if self.is_none() { - None - } else { - Some(Bytes::new_unchecked(self.0.clone())) + pub fn to_enum(&self) -> BoolUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 0 => True::new_unchecked(inner).into(), + 1 => False::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), } } - pub fn as_reader<'r>(&'r self) -> AppReader<'r> { - AppReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> BoolReader<'r> { + BoolReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for App { - type Builder = AppBuilder; - const NAME: &'static str = "App"; +impl molecule::prelude::Entity for Bool { + type Builder = BoolBuilder; + const NAME: &'static str = "Bool"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - App(data) + Bool(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -3091,21 +3587,21 @@ impl molecule::prelude::Entity for App { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AppReader::from_slice(slice).map(|reader| reader.to_entity()) + BoolReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AppReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + BoolReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set(self.to_opt()) + Self::new_builder().set(self.to_enum()) } } #[derive(Clone, Copy)] -pub struct AppReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for AppReader<'r> { +pub struct BoolReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BoolReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -3114,223 +3610,231 @@ impl<'r> ::core::fmt::LowerHex for AppReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for AppReader<'r> { +impl<'r> ::core::fmt::Debug for BoolReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for AppReader<'r> { +impl<'r> ::core::fmt::Display for BoolReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - if let Some(v) = self.to_opt() { - write!(f, "{}(Some({}))", Self::NAME, v) - } else { - write!(f, "{}(None)", Self::NAME) - } + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") } } -impl<'r> AppReader<'r> { - pub fn is_none(&self) -> bool { - self.0.is_empty() - } - pub fn is_some(&self) -> bool { - !self.0.is_empty() +impl<'r> BoolReader<'r> { + pub const ITEMS_COUNT: usize = 2; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) } - pub fn to_opt(&self) -> Option> { - if self.is_none() { - None - } else { - Some(BytesReader::new_unchecked(self.as_slice())) + pub fn to_enum(&self) -> BoolUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 0 => TrueReader::new_unchecked(inner).into(), + 1 => FalseReader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), } } } -impl<'r> molecule::prelude::Reader<'r> for AppReader<'r> { - type Entity = App; - const NAME: &'static str = "AppReader"; +impl<'r> molecule::prelude::Reader<'r> for BoolReader<'r> { + type Entity = Bool; + const NAME: &'static str = "BoolReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - AppReader(slice) + BoolReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { - if !slice.is_empty() { - BytesReader::verify(&slice[..], compatible)?; + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); } - Ok(()) - } -} -#[derive(Debug, Default)] -pub struct AppBuilder(pub(crate) Option); -impl AppBuilder { - pub fn set(mut self, v: Option) -> Self { - self.0 = v; + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 0 => TrueReader::verify(inner_slice, compatible), + 1 => FalseReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct BoolBuilder(pub(crate) BoolUnion); +impl BoolBuilder { + pub const ITEMS_COUNT: usize = 2; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); self } } -impl molecule::prelude::Builder for AppBuilder { - type Entity = App; - const NAME: &'static str = "AppBuilder"; +impl molecule::prelude::Builder for BoolBuilder { + type Entity = Bool; + const NAME: &'static str = "BoolBuilder"; fn expected_length(&self) -> usize { - self.0 - .as_ref() - .map(|ref inner| inner.as_slice().len()) - .unwrap_or(0) + molecule::NUMBER_SIZE + self.0.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - self.0 - .as_ref() - .map(|ref inner| writer.write_all(inner.as_slice())) - .unwrap_or(Ok(())) + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - App::new_unchecked(inner.into()) + Bool::new_unchecked(inner.into()) } } -#[derive(Clone)] -pub struct Participant(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Participant { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - if f.alternate() { - write!(f, "0x")?; - } - write!(f, "{}", hex_string(self.as_slice())) +#[derive(Debug, Clone)] +pub enum BoolUnion { + True(True), + False(False), +} +#[derive(Debug, Clone, Copy)] +pub enum BoolUnionReader<'r> { + True(TrueReader<'r>), + False(FalseReader<'r>), +} +impl ::core::default::Default for BoolUnion { + fn default() -> Self { + BoolUnion::True(::core::default::Default::default()) } } -impl ::core::fmt::Debug for Participant { +impl ::core::fmt::Display for BoolUnion { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:#x})", Self::NAME, self) + match self { + BoolUnion::True(ref item) => { + write!(f, "{}::{}({})", Self::NAME, True::NAME, item) + } + BoolUnion::False(ref item) => { + write!(f, "{}::{}({})", Self::NAME, False::NAME, item) + } + } } } -impl ::core::fmt::Display for Participant { +impl<'r> ::core::fmt::Display for BoolUnionReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!( - f, - "{}: {}", - "payment_script_hash", - self.payment_script_hash() - )?; - write!( - f, - ", {}: {}", - "payment_min_capacity", - self.payment_min_capacity() - )?; - write!( - f, - ", {}: {}", - "unlock_script_hash", - self.unlock_script_hash() - )?; - write!(f, ", {}: {}", "pub_key", self.pub_key())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; + match self { + BoolUnionReader::True(ref item) => { + write!(f, "{}::{}({})", Self::NAME, True::NAME, item) + } + BoolUnionReader::False(ref item) => { + write!(f, "{}::{}({})", Self::NAME, False::NAME, item) + } } - write!(f, " }}") } } -impl ::core::default::Default for Participant { - fn default() -> Self { - let v: Vec = vec![ - 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - Participant::new_unchecked(v.into()) +impl BoolUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BoolUnion::True(ref item) => write!(f, "{}", item), + BoolUnion::False(ref item) => write!(f, "{}", item), + } } } -impl Participant { - pub const FIELD_COUNT: usize = 4; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 +impl<'r> BoolUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + BoolUnionReader::True(ref item) => write!(f, "{}", item), + BoolUnionReader::False(ref item) => write!(f, "{}", item), } } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT +} +impl ::core::convert::From for BoolUnion { + fn from(item: True) -> Self { + BoolUnion::True(item) } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() +} +impl ::core::convert::From for BoolUnion { + fn from(item: False) -> Self { + BoolUnion::False(item) } - pub fn payment_script_hash(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) +} +impl<'r> ::core::convert::From> for BoolUnionReader<'r> { + fn from(item: TrueReader<'r>) -> Self { + BoolUnionReader::True(item) } - pub fn payment_min_capacity(&self) -> Uint64 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) +} +impl<'r> ::core::convert::From> for BoolUnionReader<'r> { + fn from(item: FalseReader<'r>) -> Self { + BoolUnionReader::False(item) } - pub fn unlock_script_hash(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) +} +impl BoolUnion { + pub const NAME: &'static str = "BoolUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + BoolUnion::True(item) => item.as_bytes(), + BoolUnion::False(item) => item.as_bytes(), + } } - pub fn pub_key(&self) -> SEC1EncodedPubKey { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - SEC1EncodedPubKey::new_unchecked(self.0.slice(start..end)) - } else { - SEC1EncodedPubKey::new_unchecked(self.0.slice(start..)) + pub fn as_slice(&self) -> &[u8] { + match self { + BoolUnion::True(item) => item.as_slice(), + BoolUnion::False(item) => item.as_slice(), } } - pub fn as_reader<'r>(&'r self) -> ParticipantReader<'r> { - ParticipantReader::new_unchecked(self.as_slice()) + pub fn item_id(&self) -> molecule::Number { + match self { + BoolUnion::True(_) => 0, + BoolUnion::False(_) => 1, + } } -} -impl molecule::prelude::Entity for Participant { - type Builder = ParticipantBuilder; - const NAME: &'static str = "Participant"; - fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Participant(data) + pub fn item_name(&self) -> &str { + match self { + BoolUnion::True(_) => "True", + BoolUnion::False(_) => "False", + } } - fn as_bytes(&self) -> molecule::bytes::Bytes { - self.0.clone() + pub fn as_reader<'r>(&'r self) -> BoolUnionReader<'r> { + match self { + BoolUnion::True(item) => item.as_reader().into(), + BoolUnion::False(item) => item.as_reader().into(), + } } - fn as_slice(&self) -> &[u8] { - &self.0[..] +} +impl<'r> BoolUnionReader<'r> { + pub const NAME: &'r str = "BoolUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + BoolUnionReader::True(item) => item.as_slice(), + BoolUnionReader::False(item) => item.as_slice(), + } } - fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ParticipantReader::from_slice(slice).map(|reader| reader.to_entity()) + pub fn item_id(&self) -> molecule::Number { + match self { + BoolUnionReader::True(_) => 0, + BoolUnionReader::False(_) => 1, + } } - fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ParticipantReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + pub fn item_name(&self) -> &str { + match self { + BoolUnionReader::True(_) => "True", + BoolUnionReader::False(_) => "False", + } } - fn new_builder() -> Self::Builder { - ::core::default::Default::default() +} +impl From for Bool { + fn from(value: True) -> Self { + Self::new_builder().set(value).build() } - fn as_builder(self) -> Self::Builder { - Self::new_builder() - .payment_script_hash(self.payment_script_hash()) - .payment_min_capacity(self.payment_min_capacity()) - .unlock_script_hash(self.unlock_script_hash()) - .pub_key(self.pub_key()) +} +impl From for Bool { + fn from(value: False) -> Self { + Self::new_builder().set(value).build() } } -#[derive(Clone, Copy)] -pub struct ParticipantReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ParticipantReader<'r> { +#[derive(Clone)] +pub struct A(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for A { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -3339,342 +3843,258 @@ impl<'r> ::core::fmt::LowerHex for ParticipantReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ParticipantReader<'r> { +impl ::core::fmt::Debug for A { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ParticipantReader<'r> { +impl ::core::fmt::Display for A { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!( - f, - "{}: {}", - "payment_script_hash", - self.payment_script_hash() - )?; - write!( - f, - ", {}: {}", - "payment_min_capacity", - self.payment_min_capacity() - )?; - write!( - f, - ", {}: {}", - "unlock_script_hash", - self.unlock_script_hash() - )?; - write!(f, ", {}: {}", "pub_key", self.pub_key())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> ParticipantReader<'r> { - pub const FIELD_COUNT: usize = 4; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize +impl ::core::default::Default for A { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + A::new_unchecked(v) } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } +} +impl A { + const DEFAULT_VALUE: [u8; 1] = [0]; + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() + pub fn as_reader<'r>(&'r self) -> AReader<'r> { + AReader::new_unchecked(self.as_slice()) } - pub fn payment_script_hash(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) +} +impl molecule::prelude::Entity for A { + type Builder = ABuilder; + const NAME: &'static str = "A"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + A(data) } - pub fn payment_min_capacity(&self) -> Uint64Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() } - pub fn unlock_script_hash(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + fn as_slice(&self) -> &[u8] { + &self.0[..] } - pub fn pub_key(&self) -> SEC1EncodedPubKeyReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - SEC1EncodedPubKeyReader::new_unchecked(&self.as_slice()[start..end]) - } else { - SEC1EncodedPubKeyReader::new_unchecked(&self.as_slice()[start..]) + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set([self.nth0()]) + } +} +#[derive(Clone, Copy)] +pub struct AReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for AReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; } + write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> molecule::prelude::Reader<'r> for ParticipantReader<'r> { - type Entity = Participant; - const NAME: &'static str = "ParticipantReader"; +impl<'r> ::core::fmt::Debug for AReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for AReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> AReader<'r> { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +impl<'r> molecule::prelude::Reader<'r> for AReader<'r> { + type Entity = A; + const NAME: &'static str = "AReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ParticipantReader(slice) + AReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Uint64Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; - SEC1EncodedPubKeyReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ParticipantBuilder { - pub(crate) payment_script_hash: Byte32, - pub(crate) payment_min_capacity: Uint64, - pub(crate) unlock_script_hash: Byte32, - pub(crate) pub_key: SEC1EncodedPubKey, -} -impl ParticipantBuilder { - pub const FIELD_COUNT: usize = 4; - pub fn payment_script_hash(mut self, v: Byte32) -> Self { - self.payment_script_hash = v; - self +#[derive(Clone)] +pub struct ABuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for ABuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) } - pub fn payment_min_capacity(mut self, v: Uint64) -> Self { - self.payment_min_capacity = v; - self +} +impl ::core::default::Default for ABuilder { + fn default() -> Self { + ABuilder([Byte::default()]) } - pub fn unlock_script_hash(mut self, v: Byte32) -> Self { - self.unlock_script_hash = v; +} +impl ABuilder { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn set(mut self, v: [Byte; 1]) -> Self { + self.0 = v; self } - pub fn pub_key(mut self, v: SEC1EncodedPubKey) -> Self { - self.pub_key = v; + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; self } } -impl molecule::prelude::Builder for ParticipantBuilder { - type Entity = Participant; - const NAME: &'static str = "ParticipantBuilder"; +impl molecule::prelude::Builder for ABuilder { + type Entity = A; + const NAME: &'static str = "ABuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.payment_script_hash.as_slice().len() - + self.payment_min_capacity.as_slice().len() - + self.unlock_script_hash.as_slice().len() - + self.pub_key.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.payment_script_hash.as_slice().len(); - offsets.push(total_size); - total_size += self.payment_min_capacity.as_slice().len(); - offsets.push(total_size); - total_size += self.unlock_script_hash.as_slice().len(); - offsets.push(total_size); - total_size += self.pub_key.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } - writer.write_all(self.payment_script_hash.as_slice())?; - writer.write_all(self.payment_min_capacity.as_slice())?; - writer.write_all(self.unlock_script_hash.as_slice())?; - writer.write_all(self.pub_key.as_slice())?; + writer.write_all(self.0[0].as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Participant::new_unchecked(inner.into()) + A::new_unchecked(inner.into()) } } -#[derive(Clone)] -pub struct ChannelParameters(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelParameters { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - if f.alternate() { - write!(f, "0x")?; - } - write!(f, "{}", hex_string(self.as_slice())) +impl From<[Byte; 1usize]> for A { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() } } -impl ::core::fmt::Debug for ChannelParameters { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:#x})", Self::NAME, self) +impl ::core::convert::TryFrom<&[Byte]> for A { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) } } -impl ::core::fmt::Display for ChannelParameters { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "party_a", self.party_a())?; - write!(f, ", {}: {}", "party_b", self.party_b())?; - write!(f, ", {}: {}", "nonce", self.nonce())?; - write!( - f, - ", {}: {}", - "challenge_duration", - self.challenge_duration() - )?; - write!(f, ", {}: {}", "app", self.app())?; - write!(f, ", {}: {}", "is_ledger_channel", self.is_ledger_channel())?; - write!( - f, - ", {}: {}", - "is_virtual_channel", - self.is_virtual_channel() - )?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: A) -> Self { + [value.nth0()] } } -impl ::core::default::Default for ChannelParameters { - fn default() -> Self { - let v: Vec = vec![ - 76, 1, 0, 0, 32, 0, 0, 0, 157, 0, 0, 0, 26, 1, 0, 0, 58, 1, 0, 0, 66, 1, 0, 0, 66, 1, - 0, 0, 71, 1, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, - 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - ChannelParameters::new_unchecked(v.into()) +impl From<[u8; 1usize]> for A { + fn from(value: [u8; 1usize]) -> Self { + AReader::new_unchecked(&value).to_entity() } } -impl ChannelParameters { - pub const FIELD_COUNT: usize = 7; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } +impl ::core::convert::TryFrom<&[u8]> for A { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: A) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: AReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } - pub fn party_a(&self) -> Participant { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Participant::new_unchecked(self.0.slice(start..end)) +} +impl<'a> From<&'a AReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a AReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } - pub fn party_b(&self) -> Participant { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Participant::new_unchecked(self.0.slice(start..end)) +} +#[derive(Clone)] +pub struct B(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for B { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) } - pub fn nonce(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) +} +impl ::core::fmt::Debug for B { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) } - pub fn challenge_duration(&self) -> Uint64 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - let end = molecule::unpack_number(&slice[20..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) +} +impl ::core::fmt::Display for B { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } - pub fn app(&self) -> App { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[20..]) as usize; - let end = molecule::unpack_number(&slice[24..]) as usize; - App::new_unchecked(self.0.slice(start..end)) +} +impl ::core::default::Default for B { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + B::new_unchecked(v) } - pub fn is_ledger_channel(&self) -> Bool { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[24..]) as usize; - let end = molecule::unpack_number(&slice[28..]) as usize; - Bool::new_unchecked(self.0.slice(start..end)) +} +impl B { + const DEFAULT_VALUE: [u8; 1] = [0]; + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) } - pub fn is_virtual_channel(&self) -> Bool { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[28..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[32..]) as usize; - Bool::new_unchecked(self.0.slice(start..end)) - } else { - Bool::new_unchecked(self.0.slice(start..)) - } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() } - pub fn as_reader<'r>(&'r self) -> ChannelParametersReader<'r> { - ChannelParametersReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> BReader<'r> { + BReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ChannelParameters { - type Builder = ChannelParametersBuilder; - const NAME: &'static str = "ChannelParameters"; +impl molecule::prelude::Entity for B { + type Builder = BBuilder; + const NAME: &'static str = "B"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelParameters(data) + B(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -3683,28 +4103,21 @@ impl molecule::prelude::Entity for ChannelParameters { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelParametersReader::from_slice(slice).map(|reader| reader.to_entity()) + BReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelParametersReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + BReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .party_a(self.party_a()) - .party_b(self.party_b()) - .nonce(self.nonce()) - .challenge_duration(self.challenge_duration()) - .app(self.app()) - .is_ledger_channel(self.is_ledger_channel()) - .is_virtual_channel(self.is_virtual_channel()) + Self::new_builder().set([self.nth0()]) } } #[derive(Clone, Copy)] -pub struct ChannelParametersReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelParametersReader<'r> { +pub struct BReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -3713,256 +4126,143 @@ impl<'r> ::core::fmt::LowerHex for ChannelParametersReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelParametersReader<'r> { +impl<'r> ::core::fmt::Debug for BReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelParametersReader<'r> { +impl<'r> ::core::fmt::Display for BReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "party_a", self.party_a())?; - write!(f, ", {}: {}", "party_b", self.party_b())?; - write!(f, ", {}: {}", "nonce", self.nonce())?; - write!( - f, - ", {}: {}", - "challenge_duration", - self.challenge_duration() - )?; - write!(f, ", {}: {}", "app", self.app())?; - write!(f, ", {}: {}", "is_ledger_channel", self.is_ledger_channel())?; - write!( - f, - ", {}: {}", - "is_virtual_channel", - self.is_virtual_channel() - )?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> ChannelParametersReader<'r> { - pub const FIELD_COUNT: usize = 7; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } - pub fn party_a(&self) -> ParticipantReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - ParticipantReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn party_b(&self) -> ParticipantReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - ParticipantReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn nonce(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn challenge_duration(&self) -> Uint64Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - let end = molecule::unpack_number(&slice[20..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn app(&self) -> AppReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[20..]) as usize; - let end = molecule::unpack_number(&slice[24..]) as usize; - AppReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn is_ledger_channel(&self) -> BoolReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[24..]) as usize; - let end = molecule::unpack_number(&slice[28..]) as usize; - BoolReader::new_unchecked(&self.as_slice()[start..end]) +impl<'r> BReader<'r> { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) } - pub fn is_virtual_channel(&self) -> BoolReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[28..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[32..]) as usize; - BoolReader::new_unchecked(&self.as_slice()[start..end]) - } else { - BoolReader::new_unchecked(&self.as_slice()[start..]) - } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for ChannelParametersReader<'r> { - type Entity = ChannelParameters; - const NAME: &'static str = "ChannelParametersReader"; +impl<'r> molecule::prelude::Reader<'r> for BReader<'r> { + type Entity = B; + const NAME: &'static str = "BReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelParametersReader(slice) + BReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - ParticipantReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - ParticipantReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; - Uint64Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; - AppReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; - BoolReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; - BoolReader::verify(&slice[offsets[6]..offsets[7]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ChannelParametersBuilder { - pub(crate) party_a: Participant, - pub(crate) party_b: Participant, - pub(crate) nonce: Byte32, - pub(crate) challenge_duration: Uint64, - pub(crate) app: App, - pub(crate) is_ledger_channel: Bool, - pub(crate) is_virtual_channel: Bool, -} -impl ChannelParametersBuilder { - pub const FIELD_COUNT: usize = 7; - pub fn party_a(mut self, v: Participant) -> Self { - self.party_a = v; - self - } - pub fn party_b(mut self, v: Participant) -> Self { - self.party_b = v; - self - } - pub fn nonce(mut self, v: Byte32) -> Self { - self.nonce = v; - self - } - pub fn challenge_duration(mut self, v: Uint64) -> Self { - self.challenge_duration = v; - self +#[derive(Clone)] +pub struct BBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for BBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) } - pub fn app(mut self, v: App) -> Self { - self.app = v; - self +} +impl ::core::default::Default for BBuilder { + fn default() -> Self { + BBuilder([Byte::default()]) } - pub fn is_ledger_channel(mut self, v: Bool) -> Self { - self.is_ledger_channel = v; +} +impl BBuilder { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn set(mut self, v: [Byte; 1]) -> Self { + self.0 = v; self } - pub fn is_virtual_channel(mut self, v: Bool) -> Self { - self.is_virtual_channel = v; + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; self } } -impl molecule::prelude::Builder for ChannelParametersBuilder { - type Entity = ChannelParameters; - const NAME: &'static str = "ChannelParametersBuilder"; +impl molecule::prelude::Builder for BBuilder { + type Entity = B; + const NAME: &'static str = "BBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.party_a.as_slice().len() - + self.party_b.as_slice().len() - + self.nonce.as_slice().len() - + self.challenge_duration.as_slice().len() - + self.app.as_slice().len() - + self.is_ledger_channel.as_slice().len() - + self.is_virtual_channel.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.party_a.as_slice().len(); - offsets.push(total_size); - total_size += self.party_b.as_slice().len(); - offsets.push(total_size); - total_size += self.nonce.as_slice().len(); - offsets.push(total_size); - total_size += self.challenge_duration.as_slice().len(); - offsets.push(total_size); - total_size += self.app.as_slice().len(); - offsets.push(total_size); - total_size += self.is_ledger_channel.as_slice().len(); - offsets.push(total_size); - total_size += self.is_virtual_channel.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } - writer.write_all(self.party_a.as_slice())?; - writer.write_all(self.party_b.as_slice())?; - writer.write_all(self.nonce.as_slice())?; - writer.write_all(self.challenge_duration.as_slice())?; - writer.write_all(self.app.as_slice())?; - writer.write_all(self.is_ledger_channel.as_slice())?; - writer.write_all(self.is_virtual_channel.as_slice())?; + writer.write_all(self.0[0].as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelParameters::new_unchecked(inner.into()) + B::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for B { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for B { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: B) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for B { + fn from(value: [u8; 1usize]) -> Self { + BReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for B { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: B) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: BReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a BReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a BReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct ChannelConstants(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelConstants { +pub struct App(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for App { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -3971,155 +4271,167 @@ impl ::core::fmt::LowerHex for ChannelConstants { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ChannelConstants { +impl ::core::fmt::Debug for App { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ChannelConstants { +impl ::core::fmt::Display for App { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "params", self.params())?; - write!(f, ", {}: {}", "pfls_code_hash", self.pfls_code_hash())?; - write!(f, ", {}: {}", "pfls_hash_type", self.pfls_hash_type())?; - write!(f, ", {}: {}", "pfls_min_capacity", self.pfls_min_capacity())?; - write!(f, ", {}: {}", "pcls_code_hash", self.pcls_code_hash())?; - write!(f, ", {}: {}", "pcls_hash_type", self.pcls_hash_type())?; - write!(f, ", {}: {}", "thread_token", self.thread_token())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) } - write!(f, " }}") } } -impl ::core::default::Default for ChannelConstants { +impl ::core::default::Default for App { fn default() -> Self { - let v: Vec = vec![ - 218, 1, 0, 0, 32, 0, 0, 0, 108, 1, 0, 0, 140, 1, 0, 0, 141, 1, 0, 0, 149, 1, 0, 0, 181, - 1, 0, 0, 182, 1, 0, 0, 76, 1, 0, 0, 32, 0, 0, 0, 157, 0, 0, 0, 26, 1, 0, 0, 58, 1, 0, - 0, 66, 1, 0, 0, 66, 1, 0, 0, 71, 1, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, - 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, - 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - ChannelConstants::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + App::new_unchecked(v) } } -impl ChannelConstants { - pub const FIELD_COUNT: usize = 7; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize +impl App { + const DEFAULT_VALUE: [u8; 0] = []; + pub fn is_none(&self) -> bool { + self.0.is_empty() } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option { + if self.is_none() { + None } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + Some(Bytes::new_unchecked(self.0.clone())) } } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT + pub fn as_reader<'r>(&'r self) -> AppReader<'r> { + AppReader::new_unchecked(self.as_slice()) } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() +} +impl molecule::prelude::Entity for App { + type Builder = AppBuilder; + const NAME: &'static str = "App"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + App(data) } - pub fn params(&self) -> ChannelParameters { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelParameters::new_unchecked(self.0.slice(start..end)) + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() } - pub fn pfls_code_hash(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + fn as_slice(&self) -> &[u8] { + &self.0[..] } - pub fn pfls_hash_type(&self) -> Byte { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Byte::new_unchecked(self.0.slice(start..end)) + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AppReader::from_slice(slice).map(|reader| reader.to_entity()) } - pub fn pfls_min_capacity(&self) -> Uint64 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - let end = molecule::unpack_number(&slice[20..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AppReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } - pub fn pcls_code_hash(&self) -> Byte32 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[20..]) as usize; - let end = molecule::unpack_number(&slice[24..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + fn new_builder() -> Self::Builder { + ::core::default::Default::default() } - pub fn pcls_hash_type(&self) -> Byte { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[24..]) as usize; - let end = molecule::unpack_number(&slice[28..]) as usize; - Byte::new_unchecked(self.0.slice(start..end)) + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_opt()) } - pub fn thread_token(&self) -> ChannelToken { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[28..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[32..]) as usize; - ChannelToken::new_unchecked(self.0.slice(start..end)) +} +#[derive(Clone, Copy)] +pub struct AppReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for AppReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for AppReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for AppReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) } else { - ChannelToken::new_unchecked(self.0.slice(start..)) + write!(f, "{}(None)", Self::NAME) } } - pub fn as_reader<'r>(&'r self) -> ChannelConstantsReader<'r> { - ChannelConstantsReader::new_unchecked(self.as_slice()) +} +impl<'r> AppReader<'r> { + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option> { + if self.is_none() { + None + } else { + Some(BytesReader::new_unchecked(self.as_slice())) + } } } -impl molecule::prelude::Entity for ChannelConstants { - type Builder = ChannelConstantsBuilder; - const NAME: &'static str = "ChannelConstants"; - fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelConstants(data) +impl<'r> molecule::prelude::Reader<'r> for AppReader<'r> { + type Entity = App; + const NAME: &'static str = "AppReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } - fn as_bytes(&self) -> molecule::bytes::Bytes { - self.0.clone() + fn new_unchecked(slice: &'r [u8]) -> Self { + AppReader(slice) } - fn as_slice(&self) -> &[u8] { - &self.0[..] + fn as_slice(&self) -> &'r [u8] { + self.0 } - fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelConstantsReader::from_slice(slice).map(|reader| reader.to_entity()) + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + if !slice.is_empty() { + BytesReader::verify(&slice[..], compatible)?; + } + Ok(()) } - fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelConstantsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) +} +#[derive(Clone, Debug, Default)] +pub struct AppBuilder(pub(crate) Option); +impl AppBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self } - fn new_builder() -> Self::Builder { - ::core::default::Default::default() +} +impl molecule::prelude::Builder for AppBuilder { + type Entity = App; + const NAME: &'static str = "AppBuilder"; + fn expected_length(&self) -> usize { + self.0 + .as_ref() + .map(|ref inner| inner.as_slice().len()) + .unwrap_or(0) } - fn as_builder(self) -> Self::Builder { - Self::new_builder() - .params(self.params()) - .pfls_code_hash(self.pfls_code_hash()) - .pfls_hash_type(self.pfls_hash_type()) - .pfls_min_capacity(self.pfls_min_capacity()) - .pcls_code_hash(self.pcls_code_hash()) - .pcls_hash_type(self.pcls_hash_type()) - .thread_token(self.thread_token()) + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + self.0 + .as_ref() + .map(|ref inner| writer.write_all(inner.as_slice())) + .unwrap_or(Ok(())) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + App::new_unchecked(inner.into()) } } -#[derive(Clone, Copy)] -pub struct ChannelConstantsReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelConstantsReader<'r> { +impl From for App { + fn from(value: Bytes) -> Self { + Self::new_builder().set(Some(value)).build() + } +} +#[derive(Clone)] +pub struct Participant(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Participant { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4128,21 +4440,33 @@ impl<'r> ::core::fmt::LowerHex for ChannelConstantsReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelConstantsReader<'r> { +impl ::core::fmt::Debug for Participant { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelConstantsReader<'r> { +impl ::core::fmt::Display for Participant { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "params", self.params())?; - write!(f, ", {}: {}", "pfls_code_hash", self.pfls_code_hash())?; - write!(f, ", {}: {}", "pfls_hash_type", self.pfls_hash_type())?; - write!(f, ", {}: {}", "pfls_min_capacity", self.pfls_min_capacity())?; - write!(f, ", {}: {}", "pcls_code_hash", self.pcls_code_hash())?; - write!(f, ", {}: {}", "pcls_hash_type", self.pcls_hash_type())?; - write!(f, ", {}: {}", "thread_token", self.thread_token())?; + write!( + f, + "{}: {}", + "payment_script_hash", + self.payment_script_hash() + )?; + write!( + f, + ", {}: {}", + "payment_min_capacity", + self.payment_min_capacity() + )?; + write!( + f, + ", {}: {}", + "unlock_script_hash", + self.unlock_script_hash() + )?; + write!(f, ", {}: {}", "pub_key", self.pub_key())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -4150,8 +4474,21 @@ impl<'r> ::core::fmt::Display for ChannelConstantsReader<'r> { write!(f, " }}") } } -impl<'r> ChannelConstantsReader<'r> { - pub const FIELD_COUNT: usize = 7; +impl ::core::default::Default for Participant { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Participant::new_unchecked(v) + } +} +impl Participant { + const DEFAULT_VALUE: [u8; 125] = [ + 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -4168,206 +4505,279 @@ impl<'r> ChannelConstantsReader<'r> { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn params(&self) -> ChannelParametersReader<'r> { + pub fn payment_script_hash(&self) -> Byte32 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelParametersReader::new_unchecked(&self.as_slice()[start..end]) + Byte32::new_unchecked(self.0.slice(start..end)) } - pub fn pfls_code_hash(&self) -> Byte32Reader<'r> { + pub fn payment_min_capacity(&self) -> Uint64 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; let end = molecule::unpack_number(&slice[12..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + Uint64::new_unchecked(self.0.slice(start..end)) } - pub fn pfls_hash_type(&self) -> ByteReader<'r> { + pub fn unlock_script_hash(&self) -> Byte32 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[12..]) as usize; let end = molecule::unpack_number(&slice[16..]) as usize; - ByteReader::new_unchecked(&self.as_slice()[start..end]) + Byte32::new_unchecked(self.0.slice(start..end)) } - pub fn pfls_min_capacity(&self) -> Uint64Reader<'r> { + pub fn pub_key(&self) -> SEC1EncodedPubKey { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[16..]) as usize; - let end = molecule::unpack_number(&slice[20..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn pcls_code_hash(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[20..]) as usize; - let end = molecule::unpack_number(&slice[24..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn pcls_hash_type(&self) -> ByteReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[24..]) as usize; - let end = molecule::unpack_number(&slice[28..]) as usize; - ByteReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn thread_token(&self) -> ChannelTokenReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[28..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[32..]) as usize; - ChannelTokenReader::new_unchecked(&self.as_slice()[start..end]) + let end = molecule::unpack_number(&slice[20..]) as usize; + SEC1EncodedPubKey::new_unchecked(self.0.slice(start..end)) } else { - ChannelTokenReader::new_unchecked(&self.as_slice()[start..]) + SEC1EncodedPubKey::new_unchecked(self.0.slice(start..)) } } + pub fn as_reader<'r>(&'r self) -> ParticipantReader<'r> { + ParticipantReader::new_unchecked(self.as_slice()) + } } -impl<'r> molecule::prelude::Reader<'r> for ChannelConstantsReader<'r> { - type Entity = ChannelConstants; - const NAME: &'static str = "ChannelConstantsReader"; - fn to_entity(&self) -> Self::Entity { - Self::Entity::new_unchecked(self.as_slice().to_owned().into()) +impl molecule::prelude::Entity for Participant { + type Builder = ParticipantBuilder; + const NAME: &'static str = "Participant"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Participant(data) } - fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelConstantsReader(slice) + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() } - fn as_slice(&self) -> &'r [u8] { - self.0 + fn as_slice(&self) -> &[u8] { + &self.0[..] } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { - use molecule::verification_error as ve; - let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); - } - ChannelParametersReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - ByteReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; - Uint64Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; - Byte32Reader::verify(&slice[offsets[4]..offsets[5]], compatible)?; - ByteReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; - ChannelTokenReader::verify(&slice[offsets[6]..offsets[7]], compatible)?; - Ok(()) + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ParticipantReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ParticipantReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .payment_script_hash(self.payment_script_hash()) + .payment_min_capacity(self.payment_min_capacity()) + .unlock_script_hash(self.unlock_script_hash()) + .pub_key(self.pub_key()) } } -#[derive(Debug, Default)] -pub struct ChannelConstantsBuilder { - pub(crate) params: ChannelParameters, - pub(crate) pfls_code_hash: Byte32, - pub(crate) pfls_hash_type: Byte, - pub(crate) pfls_min_capacity: Uint64, - pub(crate) pcls_code_hash: Byte32, - pub(crate) pcls_hash_type: Byte, - pub(crate) thread_token: ChannelToken, +#[derive(Clone, Copy)] +pub struct ParticipantReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ParticipantReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } } -impl ChannelConstantsBuilder { - pub const FIELD_COUNT: usize = 7; - pub fn params(mut self, v: ChannelParameters) -> Self { - self.params = v; - self +impl<'r> ::core::fmt::Debug for ParticipantReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) } - pub fn pfls_code_hash(mut self, v: Byte32) -> Self { - self.pfls_code_hash = v; - self +} +impl<'r> ::core::fmt::Display for ParticipantReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!( + f, + "{}: {}", + "payment_script_hash", + self.payment_script_hash() + )?; + write!( + f, + ", {}: {}", + "payment_min_capacity", + self.payment_min_capacity() + )?; + write!( + f, + ", {}: {}", + "unlock_script_hash", + self.unlock_script_hash() + )?; + write!(f, ", {}: {}", "pub_key", self.pub_key())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } - pub fn pfls_hash_type(mut self, v: Byte) -> Self { - self.pfls_hash_type = v; - self +} +impl<'r> ParticipantReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn pfls_min_capacity(mut self, v: Uint64) -> Self { - self.pfls_min_capacity = v; + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn payment_script_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn payment_min_capacity(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn unlock_script_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pub_key(&self) -> SEC1EncodedPubKeyReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + SEC1EncodedPubKeyReader::new_unchecked(&self.as_slice()[start..end]) + } else { + SEC1EncodedPubKeyReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ParticipantReader<'r> { + type Entity = Participant; + const NAME: &'static str = "ParticipantReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ParticipantReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint64Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + SEC1EncodedPubKeyReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ParticipantBuilder { + pub(crate) payment_script_hash: Byte32, + pub(crate) payment_min_capacity: Uint64, + pub(crate) unlock_script_hash: Byte32, + pub(crate) pub_key: SEC1EncodedPubKey, +} +impl ParticipantBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn payment_script_hash(mut self, v: Byte32) -> Self { + self.payment_script_hash = v; self } - pub fn pcls_code_hash(mut self, v: Byte32) -> Self { - self.pcls_code_hash = v; + pub fn payment_min_capacity(mut self, v: Uint64) -> Self { + self.payment_min_capacity = v; self } - pub fn pcls_hash_type(mut self, v: Byte) -> Self { - self.pcls_hash_type = v; + pub fn unlock_script_hash(mut self, v: Byte32) -> Self { + self.unlock_script_hash = v; self } - pub fn thread_token(mut self, v: ChannelToken) -> Self { - self.thread_token = v; + pub fn pub_key(mut self, v: SEC1EncodedPubKey) -> Self { + self.pub_key = v; self } } -impl molecule::prelude::Builder for ChannelConstantsBuilder { - type Entity = ChannelConstants; - const NAME: &'static str = "ChannelConstantsBuilder"; +impl molecule::prelude::Builder for ParticipantBuilder { + type Entity = Participant; + const NAME: &'static str = "ParticipantBuilder"; fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.params.as_slice().len() - + self.pfls_code_hash.as_slice().len() - + self.pfls_hash_type.as_slice().len() - + self.pfls_min_capacity.as_slice().len() - + self.pcls_code_hash.as_slice().len() - + self.pcls_hash_type.as_slice().len() - + self.thread_token.as_slice().len() + + self.payment_script_hash.as_slice().len() + + self.payment_min_capacity.as_slice().len() + + self.unlock_script_hash.as_slice().len() + + self.pub_key.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); offsets.push(total_size); - total_size += self.params.as_slice().len(); - offsets.push(total_size); - total_size += self.pfls_code_hash.as_slice().len(); - offsets.push(total_size); - total_size += self.pfls_hash_type.as_slice().len(); - offsets.push(total_size); - total_size += self.pfls_min_capacity.as_slice().len(); + total_size += self.payment_script_hash.as_slice().len(); offsets.push(total_size); - total_size += self.pcls_code_hash.as_slice().len(); + total_size += self.payment_min_capacity.as_slice().len(); offsets.push(total_size); - total_size += self.pcls_hash_type.as_slice().len(); + total_size += self.unlock_script_hash.as_slice().len(); offsets.push(total_size); - total_size += self.thread_token.as_slice().len(); + total_size += self.pub_key.as_slice().len(); writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; for offset in offsets.into_iter() { writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } - writer.write_all(self.params.as_slice())?; - writer.write_all(self.pfls_code_hash.as_slice())?; - writer.write_all(self.pfls_hash_type.as_slice())?; - writer.write_all(self.pfls_min_capacity.as_slice())?; - writer.write_all(self.pcls_code_hash.as_slice())?; - writer.write_all(self.pcls_hash_type.as_slice())?; - writer.write_all(self.thread_token.as_slice())?; + writer.write_all(self.payment_script_hash.as_slice())?; + writer.write_all(self.payment_min_capacity.as_slice())?; + writer.write_all(self.unlock_script_hash.as_slice())?; + writer.write_all(self.pub_key.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelConstants::new_unchecked(inner.into()) + Participant::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Fund(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Fund { +pub struct ChannelParameters(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelParameters { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4376,43 +4786,131 @@ impl ::core::fmt::LowerHex for Fund { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Fund { +impl ::core::fmt::Debug for ChannelParameters { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Fund { +impl ::core::fmt::Display for ChannelParameters { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) - } -} -impl ::core::default::Default for Fund { - fn default() -> Self { - let v: Vec = vec![0]; - Fund::new_unchecked(v.into()) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "party_a", self.party_a())?; + write!(f, ", {}: {}", "party_b", self.party_b())?; + write!(f, ", {}: {}", "nonce", self.nonce())?; + write!( + f, + ", {}: {}", + "challenge_duration", + self.challenge_duration() + )?; + write!(f, ", {}: {}", "app", self.app())?; + write!(f, ", {}: {}", "is_ledger_channel", self.is_ledger_channel())?; + write!( + f, + ", {}: {}", + "is_virtual_channel", + self.is_virtual_channel() + )?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl Fund { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> Byte { - Byte::new_unchecked(self.0.slice(0..1)) +impl ::core::default::Default for ChannelParameters { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelParameters::new_unchecked(v) } - pub fn raw_data(&self) -> molecule::bytes::Bytes { - self.as_bytes() +} +impl ChannelParameters { + const DEFAULT_VALUE: [u8; 332] = [ + 76, 1, 0, 0, 32, 0, 0, 0, 157, 0, 0, 0, 26, 1, 0, 0, 58, 1, 0, 0, 66, 1, 0, 0, 66, 1, 0, 0, + 71, 1, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 7; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn as_reader<'r>(&'r self) -> FundReader<'r> { - FundReader::new_unchecked(self.as_slice()) + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn party_a(&self) -> Participant { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Participant::new_unchecked(self.0.slice(start..end)) + } + pub fn party_b(&self) -> Participant { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Participant::new_unchecked(self.0.slice(start..end)) + } + pub fn nonce(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn challenge_duration(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } + pub fn app(&self) -> App { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + App::new_unchecked(self.0.slice(start..end)) + } + pub fn is_ledger_channel(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + let end = molecule::unpack_number(&slice[28..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } + pub fn is_virtual_channel(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[28..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[32..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } else { + Bool::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ChannelParametersReader<'r> { + ChannelParametersReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Fund { - type Builder = FundBuilder; - const NAME: &'static str = "Fund"; +impl molecule::prelude::Entity for ChannelParameters { + type Builder = ChannelParametersBuilder; + const NAME: &'static str = "ChannelParameters"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Fund(data) + ChannelParameters(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -4421,21 +4919,28 @@ impl molecule::prelude::Entity for Fund { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - FundReader::from_slice(slice).map(|reader| reader.to_entity()) + ChannelParametersReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - FundReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + ChannelParametersReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set([self.nth0()]) + Self::new_builder() + .party_a(self.party_a()) + .party_b(self.party_b()) + .nonce(self.nonce()) + .challenge_duration(self.challenge_duration()) + .app(self.app()) + .is_ledger_channel(self.is_ledger_channel()) + .is_virtual_channel(self.is_virtual_channel()) } } #[derive(Clone, Copy)] -pub struct FundReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for FundReader<'r> { +pub struct ChannelParametersReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelParametersReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4444,94 +4949,253 @@ impl<'r> ::core::fmt::LowerHex for FundReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for FundReader<'r> { +impl<'r> ::core::fmt::Debug for ChannelParametersReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for FundReader<'r> { +impl<'r> ::core::fmt::Display for ChannelParametersReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "party_a", self.party_a())?; + write!(f, ", {}: {}", "party_b", self.party_b())?; + write!(f, ", {}: {}", "nonce", self.nonce())?; + write!( + f, + ", {}: {}", + "challenge_duration", + self.challenge_duration() + )?; + write!(f, ", {}: {}", "app", self.app())?; + write!(f, ", {}: {}", "is_ledger_channel", self.is_ledger_channel())?; + write!( + f, + ", {}: {}", + "is_virtual_channel", + self.is_virtual_channel() + )?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl<'r> FundReader<'r> { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> ByteReader<'r> { - ByteReader::new_unchecked(&self.as_slice()[0..1]) +impl<'r> ChannelParametersReader<'r> { + pub const FIELD_COUNT: usize = 7; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> &'r [u8] { - self.as_slice() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn party_a(&self) -> ParticipantReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ParticipantReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn party_b(&self) -> ParticipantReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + ParticipantReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn nonce(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn challenge_duration(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn app(&self) -> AppReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + AppReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn is_ledger_channel(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + let end = molecule::unpack_number(&slice[28..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn is_virtual_channel(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[28..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[32..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BoolReader::new_unchecked(&self.as_slice()[start..]) + } } } -impl<'r> molecule::prelude::Reader<'r> for FundReader<'r> { - type Entity = Fund; - const NAME: &'static str = "FundReader"; +impl<'r> molecule::prelude::Reader<'r> for ChannelParametersReader<'r> { + type Entity = ChannelParameters; + const NAME: &'static str = "ChannelParametersReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - FundReader(slice) + ChannelParametersReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len != Self::TOTAL_SIZE { - return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); } - Ok(()) - } -} -pub struct FundBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for FundBuilder { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:?})", Self::NAME, &self.0[..]) - } -} -impl ::core::default::Default for FundBuilder { - fn default() -> Self { - FundBuilder([Byte::default()]) - } -} -impl FundBuilder { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn set(mut self, v: [Byte; 1]) -> Self { - self.0 = v; + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ParticipantReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + ParticipantReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Uint64Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + AppReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + BoolReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; + BoolReader::verify(&slice[offsets[6]..offsets[7]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ChannelParametersBuilder { + pub(crate) party_a: Participant, + pub(crate) party_b: Participant, + pub(crate) nonce: Byte32, + pub(crate) challenge_duration: Uint64, + pub(crate) app: App, + pub(crate) is_ledger_channel: Bool, + pub(crate) is_virtual_channel: Bool, +} +impl ChannelParametersBuilder { + pub const FIELD_COUNT: usize = 7; + pub fn party_a(mut self, v: Participant) -> Self { + self.party_a = v; self } - pub fn nth0(mut self, v: Byte) -> Self { - self.0[0] = v; + pub fn party_b(mut self, v: Participant) -> Self { + self.party_b = v; + self + } + pub fn nonce(mut self, v: Byte32) -> Self { + self.nonce = v; + self + } + pub fn challenge_duration(mut self, v: Uint64) -> Self { + self.challenge_duration = v; + self + } + pub fn app(mut self, v: App) -> Self { + self.app = v; + self + } + pub fn is_ledger_channel(mut self, v: Bool) -> Self { + self.is_ledger_channel = v; + self + } + pub fn is_virtual_channel(mut self, v: Bool) -> Self { + self.is_virtual_channel = v; self } } -impl molecule::prelude::Builder for FundBuilder { - type Entity = Fund; - const NAME: &'static str = "FundBuilder"; +impl molecule::prelude::Builder for ChannelParametersBuilder { + type Entity = ChannelParameters; + const NAME: &'static str = "ChannelParametersBuilder"; fn expected_length(&self) -> usize { - Self::TOTAL_SIZE + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.party_a.as_slice().len() + + self.party_b.as_slice().len() + + self.nonce.as_slice().len() + + self.challenge_duration.as_slice().len() + + self.app.as_slice().len() + + self.is_ledger_channel.as_slice().len() + + self.is_virtual_channel.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(self.0[0].as_slice())?; + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.party_a.as_slice().len(); + offsets.push(total_size); + total_size += self.party_b.as_slice().len(); + offsets.push(total_size); + total_size += self.nonce.as_slice().len(); + offsets.push(total_size); + total_size += self.challenge_duration.as_slice().len(); + offsets.push(total_size); + total_size += self.app.as_slice().len(); + offsets.push(total_size); + total_size += self.is_ledger_channel.as_slice().len(); + offsets.push(total_size); + total_size += self.is_virtual_channel.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.party_a.as_slice())?; + writer.write_all(self.party_b.as_slice())?; + writer.write_all(self.nonce.as_slice())?; + writer.write_all(self.challenge_duration.as_slice())?; + writer.write_all(self.app.as_slice())?; + writer.write_all(self.is_ledger_channel.as_slice())?; + writer.write_all(self.is_virtual_channel.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Fund::new_unchecked(inner.into()) + ChannelParameters::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Abort(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Abort { +pub struct ChannelConstants(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4540,43 +5204,126 @@ impl ::core::fmt::LowerHex for Abort { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Abort { +impl ::core::fmt::Debug for ChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Abort { +impl ::core::fmt::Display for ChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "params", self.params())?; + write!(f, ", {}: {}", "pfls_code_hash", self.pfls_code_hash())?; + write!(f, ", {}: {}", "pfls_hash_type", self.pfls_hash_type())?; + write!(f, ", {}: {}", "pfls_min_capacity", self.pfls_min_capacity())?; + write!(f, ", {}: {}", "pcls_code_hash", self.pcls_code_hash())?; + write!(f, ", {}: {}", "pcls_hash_type", self.pcls_hash_type())?; + write!(f, ", {}: {}", "thread_token", self.thread_token())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl ::core::default::Default for Abort { +impl ::core::default::Default for ChannelConstants { fn default() -> Self { - let v: Vec = vec![0]; - Abort::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelConstants::new_unchecked(v) } } -impl Abort { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> Byte { - Byte::new_unchecked(self.0.slice(0..1)) +impl ChannelConstants { + const DEFAULT_VALUE: [u8; 474] = [ + 218, 1, 0, 0, 32, 0, 0, 0, 108, 1, 0, 0, 140, 1, 0, 0, 141, 1, 0, 0, 149, 1, 0, 0, 181, 1, + 0, 0, 182, 1, 0, 0, 76, 1, 0, 0, 32, 0, 0, 0, 157, 0, 0, 0, 26, 1, 0, 0, 58, 1, 0, 0, 66, + 1, 0, 0, 66, 1, 0, 0, 71, 1, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, + 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 7; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> molecule::bytes::Bytes { - self.as_bytes() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } - pub fn as_reader<'r>(&'r self) -> AbortReader<'r> { - AbortReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn params(&self) -> ChannelParameters { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelParameters::new_unchecked(self.0.slice(start..end)) + } + pub fn pfls_code_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn pfls_hash_type(&self) -> Byte { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn pfls_min_capacity(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } + pub fn pcls_code_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn pcls_hash_type(&self) -> Byte { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + let end = molecule::unpack_number(&slice[28..]) as usize; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn thread_token(&self) -> ChannelToken { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[28..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[32..]) as usize; + ChannelToken::new_unchecked(self.0.slice(start..end)) + } else { + ChannelToken::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ChannelConstantsReader<'r> { + ChannelConstantsReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Abort { - type Builder = AbortBuilder; - const NAME: &'static str = "Abort"; +impl molecule::prelude::Entity for ChannelConstants { + type Builder = ChannelConstantsBuilder; + const NAME: &'static str = "ChannelConstants"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Abort(data) + ChannelConstants(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -4585,21 +5332,28 @@ impl molecule::prelude::Entity for Abort { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AbortReader::from_slice(slice).map(|reader| reader.to_entity()) + ChannelConstantsReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - AbortReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + ChannelConstantsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set([self.nth0()]) + Self::new_builder() + .params(self.params()) + .pfls_code_hash(self.pfls_code_hash()) + .pfls_hash_type(self.pfls_hash_type()) + .pfls_min_capacity(self.pfls_min_capacity()) + .pcls_code_hash(self.pcls_code_hash()) + .pcls_hash_type(self.pcls_hash_type()) + .thread_token(self.thread_token()) } } #[derive(Clone, Copy)] -pub struct AbortReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for AbortReader<'r> { +pub struct ChannelConstantsReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4608,94 +5362,243 @@ impl<'r> ::core::fmt::LowerHex for AbortReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for AbortReader<'r> { +impl<'r> ::core::fmt::Debug for ChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for AbortReader<'r> { +impl<'r> ::core::fmt::Display for ChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use molecule::hex_string; - let raw_data = hex_string(&self.raw_data()); - write!(f, "{}(0x{})", Self::NAME, raw_data) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "params", self.params())?; + write!(f, ", {}: {}", "pfls_code_hash", self.pfls_code_hash())?; + write!(f, ", {}: {}", "pfls_hash_type", self.pfls_hash_type())?; + write!(f, ", {}: {}", "pfls_min_capacity", self.pfls_min_capacity())?; + write!(f, ", {}: {}", "pcls_code_hash", self.pcls_code_hash())?; + write!(f, ", {}: {}", "pcls_hash_type", self.pcls_hash_type())?; + write!(f, ", {}: {}", "thread_token", self.thread_token())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl<'r> AbortReader<'r> { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn nth0(&self) -> ByteReader<'r> { - ByteReader::new_unchecked(&self.as_slice()[0..1]) +impl<'r> ChannelConstantsReader<'r> { + pub const FIELD_COUNT: usize = 7; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn raw_data(&self) -> &'r [u8] { - self.as_slice() + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn params(&self) -> ChannelParametersReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelParametersReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pfls_code_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pfls_hash_type(&self) -> ByteReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pfls_min_capacity(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pcls_code_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn pcls_hash_type(&self) -> ByteReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + let end = molecule::unpack_number(&slice[28..]) as usize; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn thread_token(&self) -> ChannelTokenReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[28..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[32..]) as usize; + ChannelTokenReader::new_unchecked(&self.as_slice()[start..end]) + } else { + ChannelTokenReader::new_unchecked(&self.as_slice()[start..]) + } } } -impl<'r> molecule::prelude::Reader<'r> for AbortReader<'r> { - type Entity = Abort; - const NAME: &'static str = "AbortReader"; +impl<'r> molecule::prelude::Reader<'r> for ChannelConstantsReader<'r> { + type Entity = ChannelConstants; + const NAME: &'static str = "ChannelConstantsReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - AbortReader(slice) + ChannelConstantsReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len != Self::TOTAL_SIZE { - return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); } + ChannelParametersReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + ByteReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Uint64Reader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Byte32Reader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + ByteReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; + ChannelTokenReader::verify(&slice[offsets[6]..offsets[7]], compatible)?; Ok(()) } } -pub struct AbortBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for AbortBuilder { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}({:?})", Self::NAME, &self.0[..]) - } +#[derive(Clone, Debug, Default)] +pub struct ChannelConstantsBuilder { + pub(crate) params: ChannelParameters, + pub(crate) pfls_code_hash: Byte32, + pub(crate) pfls_hash_type: Byte, + pub(crate) pfls_min_capacity: Uint64, + pub(crate) pcls_code_hash: Byte32, + pub(crate) pcls_hash_type: Byte, + pub(crate) thread_token: ChannelToken, } -impl ::core::default::Default for AbortBuilder { - fn default() -> Self { - AbortBuilder([Byte::default()]) +impl ChannelConstantsBuilder { + pub const FIELD_COUNT: usize = 7; + pub fn params(mut self, v: ChannelParameters) -> Self { + self.params = v; + self } -} -impl AbortBuilder { - pub const TOTAL_SIZE: usize = 1; - pub const ITEM_SIZE: usize = 1; - pub const ITEM_COUNT: usize = 1; - pub fn set(mut self, v: [Byte; 1]) -> Self { - self.0 = v; + pub fn pfls_code_hash(mut self, v: Byte32) -> Self { + self.pfls_code_hash = v; self } - pub fn nth0(mut self, v: Byte) -> Self { - self.0[0] = v; + pub fn pfls_hash_type(mut self, v: Byte) -> Self { + self.pfls_hash_type = v; + self + } + pub fn pfls_min_capacity(mut self, v: Uint64) -> Self { + self.pfls_min_capacity = v; + self + } + pub fn pcls_code_hash(mut self, v: Byte32) -> Self { + self.pcls_code_hash = v; + self + } + pub fn pcls_hash_type(mut self, v: Byte) -> Self { + self.pcls_hash_type = v; + self + } + pub fn thread_token(mut self, v: ChannelToken) -> Self { + self.thread_token = v; self } } -impl molecule::prelude::Builder for AbortBuilder { - type Entity = Abort; - const NAME: &'static str = "AbortBuilder"; +impl molecule::prelude::Builder for ChannelConstantsBuilder { + type Entity = ChannelConstants; + const NAME: &'static str = "ChannelConstantsBuilder"; fn expected_length(&self) -> usize { - Self::TOTAL_SIZE + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.params.as_slice().len() + + self.pfls_code_hash.as_slice().len() + + self.pfls_hash_type.as_slice().len() + + self.pfls_min_capacity.as_slice().len() + + self.pcls_code_hash.as_slice().len() + + self.pcls_hash_type.as_slice().len() + + self.thread_token.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(self.0[0].as_slice())?; + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.params.as_slice().len(); + offsets.push(total_size); + total_size += self.pfls_code_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.pfls_hash_type.as_slice().len(); + offsets.push(total_size); + total_size += self.pfls_min_capacity.as_slice().len(); + offsets.push(total_size); + total_size += self.pcls_code_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.pcls_hash_type.as_slice().len(); + offsets.push(total_size); + total_size += self.thread_token.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.params.as_slice())?; + writer.write_all(self.pfls_code_hash.as_slice())?; + writer.write_all(self.pfls_hash_type.as_slice())?; + writer.write_all(self.pfls_min_capacity.as_slice())?; + writer.write_all(self.pcls_code_hash.as_slice())?; + writer.write_all(self.pcls_hash_type.as_slice())?; + writer.write_all(self.thread_token.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Abort::new_unchecked(inner.into()) + ChannelConstants::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Dispute(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Dispute { +pub struct VCChannelConstants(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for VCChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4704,16 +5607,17 @@ impl ::core::fmt::LowerHex for Dispute { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Dispute { +impl ::core::fmt::Debug for VCChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Dispute { +impl ::core::fmt::Display for VCChannelConstants { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "sig_a", self.sig_a())?; - write!(f, ", {}: {}", "sig_b", self.sig_b())?; + write!(f, "{}: {}", "params", self.params())?; + write!(f, ", {}: {}", "vcls_code_hash", self.vcls_code_hash())?; + write!(f, ", {}: {}", "vcls_hash_type", self.vcls_hash_type())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -4721,16 +5625,29 @@ impl ::core::fmt::Display for Dispute { write!(f, " }}") } } -impl ::core::default::Default for Dispute { +impl ::core::default::Default for VCChannelConstants { fn default() -> Self { - let v: Vec = vec![ - 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - Dispute::new_unchecked(v.into()) - } -} -impl Dispute { - pub const FIELD_COUNT: usize = 2; + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + VCChannelConstants::new_unchecked(v) + } +} +impl VCChannelConstants { + const DEFAULT_VALUE: [u8; 381] = [ + 125, 1, 0, 0, 16, 0, 0, 0, 92, 1, 0, 0, 124, 1, 0, 0, 76, 1, 0, 0, 32, 0, 0, 0, 157, 0, 0, + 0, 26, 1, 0, 0, 58, 1, 0, 0, 66, 1, 0, 0, 66, 1, 0, 0, 71, 1, 0, 0, 125, 0, 0, 0, 20, 0, 0, + 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, + 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -4747,31 +5664,37 @@ impl Dispute { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn sig_a(&self) -> Bytes { + pub fn params(&self) -> ChannelParameters { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - Bytes::new_unchecked(self.0.slice(start..end)) + ChannelParameters::new_unchecked(self.0.slice(start..end)) } - pub fn sig_b(&self) -> Bytes { + pub fn vcls_code_hash(&self) -> Byte32 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn vcls_hash_type(&self) -> Byte { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - Bytes::new_unchecked(self.0.slice(start..end)) + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte::new_unchecked(self.0.slice(start..end)) } else { - Bytes::new_unchecked(self.0.slice(start..)) + Byte::new_unchecked(self.0.slice(start..)) } } - pub fn as_reader<'r>(&'r self) -> DisputeReader<'r> { - DisputeReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> VCChannelConstantsReader<'r> { + VCChannelConstantsReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Dispute { - type Builder = DisputeBuilder; - const NAME: &'static str = "Dispute"; +impl molecule::prelude::Entity for VCChannelConstants { + type Builder = VCChannelConstantsBuilder; + const NAME: &'static str = "VCChannelConstants"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Dispute(data) + VCChannelConstants(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -4780,21 +5703,24 @@ impl molecule::prelude::Entity for Dispute { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - DisputeReader::from_slice(slice).map(|reader| reader.to_entity()) + VCChannelConstantsReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - DisputeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + VCChannelConstantsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().sig_a(self.sig_a()).sig_b(self.sig_b()) + Self::new_builder() + .params(self.params()) + .vcls_code_hash(self.vcls_code_hash()) + .vcls_hash_type(self.vcls_hash_type()) } } #[derive(Clone, Copy)] -pub struct DisputeReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for DisputeReader<'r> { +pub struct VCChannelConstantsReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for VCChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4803,16 +5729,17 @@ impl<'r> ::core::fmt::LowerHex for DisputeReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for DisputeReader<'r> { +impl<'r> ::core::fmt::Debug for VCChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for DisputeReader<'r> { +impl<'r> ::core::fmt::Display for VCChannelConstantsReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "sig_a", self.sig_a())?; - write!(f, ", {}: {}", "sig_b", self.sig_b())?; + write!(f, "{}: {}", "params", self.params())?; + write!(f, ", {}: {}", "vcls_code_hash", self.vcls_code_hash())?; + write!(f, ", {}: {}", "vcls_hash_type", self.vcls_hash_type())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -4820,8 +5747,8 @@ impl<'r> ::core::fmt::Display for DisputeReader<'r> { write!(f, " }}") } } -impl<'r> DisputeReader<'r> { - pub const FIELD_COUNT: usize = 2; +impl<'r> VCChannelConstantsReader<'r> { + pub const FIELD_COUNT: usize = 3; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -4838,31 +5765,37 @@ impl<'r> DisputeReader<'r> { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn sig_a(&self) -> BytesReader<'r> { + pub fn params(&self) -> ChannelParametersReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - BytesReader::new_unchecked(&self.as_slice()[start..end]) + ChannelParametersReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn sig_b(&self) -> BytesReader<'r> { + pub fn vcls_code_hash(&self) -> Byte32Reader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn vcls_hash_type(&self) -> ByteReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[12..]) as usize; - BytesReader::new_unchecked(&self.as_slice()[start..end]) + let end = molecule::unpack_number(&slice[16..]) as usize; + ByteReader::new_unchecked(&self.as_slice()[start..end]) } else { - BytesReader::new_unchecked(&self.as_slice()[start..]) + ByteReader::new_unchecked(&self.as_slice()[start..]) } } } -impl<'r> molecule::prelude::Reader<'r> for DisputeReader<'r> { - type Entity = Dispute; - const NAME: &'static str = "DisputeReader"; +impl<'r> molecule::prelude::Reader<'r> for VCChannelConstantsReader<'r> { + type Entity = VCChannelConstants; + const NAME: &'static str = "VCChannelConstantsReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - DisputeReader(slice) + VCChannelConstantsReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -4877,9 +5810,6 @@ impl<'r> molecule::prelude::Reader<'r> for DisputeReader<'r> { if slice_len != total_size { return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } if slice_len < molecule::NUMBER_SIZE * 2 { return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); } @@ -4904,60 +5834,70 @@ impl<'r> molecule::prelude::Reader<'r> for DisputeReader<'r> { if offsets.windows(2).any(|i| i[0] > i[1]) { return ve!(Self, OffsetsNotMatch); } - BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + ChannelParametersReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + ByteReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct DisputeBuilder { - pub(crate) sig_a: Bytes, - pub(crate) sig_b: Bytes, +#[derive(Clone, Debug, Default)] +pub struct VCChannelConstantsBuilder { + pub(crate) params: ChannelParameters, + pub(crate) vcls_code_hash: Byte32, + pub(crate) vcls_hash_type: Byte, } -impl DisputeBuilder { - pub const FIELD_COUNT: usize = 2; - pub fn sig_a(mut self, v: Bytes) -> Self { - self.sig_a = v; +impl VCChannelConstantsBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn params(mut self, v: ChannelParameters) -> Self { + self.params = v; self } - pub fn sig_b(mut self, v: Bytes) -> Self { - self.sig_b = v; + pub fn vcls_code_hash(mut self, v: Byte32) -> Self { + self.vcls_code_hash = v; + self + } + pub fn vcls_hash_type(mut self, v: Byte) -> Self { + self.vcls_hash_type = v; self } } -impl molecule::prelude::Builder for DisputeBuilder { - type Entity = Dispute; - const NAME: &'static str = "DisputeBuilder"; +impl molecule::prelude::Builder for VCChannelConstantsBuilder { + type Entity = VCChannelConstants; + const NAME: &'static str = "VCChannelConstantsBuilder"; fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.sig_a.as_slice().len() - + self.sig_b.as_slice().len() + + self.params.as_slice().len() + + self.vcls_code_hash.as_slice().len() + + self.vcls_hash_type.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); offsets.push(total_size); - total_size += self.sig_a.as_slice().len(); + total_size += self.params.as_slice().len(); offsets.push(total_size); - total_size += self.sig_b.as_slice().len(); + total_size += self.vcls_code_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.vcls_hash_type.as_slice().len(); writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; for offset in offsets.into_iter() { writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } - writer.write_all(self.sig_a.as_slice())?; - writer.write_all(self.sig_b.as_slice())?; + writer.write_all(self.params.as_slice())?; + writer.write_all(self.vcls_code_hash.as_slice())?; + writer.write_all(self.vcls_hash_type.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Dispute::new_unchecked(inner.into()) + VCChannelConstants::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct Close(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for Close { +pub struct Fund(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Fund { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -4966,85 +5906,44 @@ impl ::core::fmt::LowerHex for Close { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for Close { +impl ::core::fmt::Debug for Fund { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for Close { +impl ::core::fmt::Display for Fund { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "state", self.state())?; - write!(f, ", {}: {}", "sig_a", self.sig_a())?; - write!(f, ", {}: {}", "sig_b", self.sig_b())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl ::core::default::Default for Close { +impl ::core::default::Default for Fund { fn default() -> Self { - let v: Vec = vec![ - 121, 0, 0, 0, 16, 0, 0, 0, 113, 0, 0, 0, 117, 0, 0, 0, 97, 0, 0, 0, 20, 0, 0, 0, 52, 0, - 0, 0, 84, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - Close::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Fund::new_unchecked(v) } } -impl Close { - pub const FIELD_COUNT: usize = 3; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } - pub fn state(&self) -> ChannelState { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelState::new_unchecked(self.0.slice(start..end)) - } - pub fn sig_a(&self) -> Bytes { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Bytes::new_unchecked(self.0.slice(start..end)) +impl Fund { + const DEFAULT_VALUE: [u8; 1] = [0]; + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) } - pub fn sig_b(&self) -> Bytes { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - Bytes::new_unchecked(self.0.slice(start..end)) - } else { - Bytes::new_unchecked(self.0.slice(start..)) - } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() } - pub fn as_reader<'r>(&'r self) -> CloseReader<'r> { - CloseReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> FundReader<'r> { + FundReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for Close { - type Builder = CloseBuilder; - const NAME: &'static str = "Close"; +impl molecule::prelude::Entity for Fund { + type Builder = FundBuilder; + const NAME: &'static str = "Fund"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - Close(data) + Fund(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -5053,24 +5952,21 @@ impl molecule::prelude::Entity for Close { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - CloseReader::from_slice(slice).map(|reader| reader.to_entity()) + FundReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - CloseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + FundReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .state(self.state()) - .sig_a(self.sig_a()) - .sig_b(self.sig_b()) + Self::new_builder().set([self.nth0()]) } } #[derive(Clone, Copy)] -pub struct CloseReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for CloseReader<'r> { +pub struct FundReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for FundReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5079,178 +5975,143 @@ impl<'r> ::core::fmt::LowerHex for CloseReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for CloseReader<'r> { +impl<'r> ::core::fmt::Debug for FundReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for CloseReader<'r> { +impl<'r> ::core::fmt::Display for FundReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "state", self.state())?; - write!(f, ", {}: {}", "sig_a", self.sig_a())?; - write!(f, ", {}: {}", "sig_b", self.sig_b())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> CloseReader<'r> { - pub const FIELD_COUNT: usize = 3; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } - pub fn state(&self) -> ChannelStateReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelStateReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn sig_a(&self) -> BytesReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - BytesReader::new_unchecked(&self.as_slice()[start..end]) +impl<'r> FundReader<'r> { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) } - pub fn sig_b(&self) -> BytesReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - BytesReader::new_unchecked(&self.as_slice()[start..end]) - } else { - BytesReader::new_unchecked(&self.as_slice()[start..]) - } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for CloseReader<'r> { - type Entity = Close; - const NAME: &'static str = "CloseReader"; +impl<'r> molecule::prelude::Reader<'r> for FundReader<'r> { + type Entity = Fund; + const NAME: &'static str = "FundReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - CloseReader(slice) + FundReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); - } - ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - BytesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct CloseBuilder { - pub(crate) state: ChannelState, - pub(crate) sig_a: Bytes, - pub(crate) sig_b: Bytes, +#[derive(Clone)] +pub struct FundBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for FundBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } } -impl CloseBuilder { - pub const FIELD_COUNT: usize = 3; - pub fn state(mut self, v: ChannelState) -> Self { - self.state = v; - self +impl ::core::default::Default for FundBuilder { + fn default() -> Self { + FundBuilder([Byte::default()]) } - pub fn sig_a(mut self, v: Bytes) -> Self { - self.sig_a = v; +} +impl FundBuilder { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn set(mut self, v: [Byte; 1]) -> Self { + self.0 = v; self } - pub fn sig_b(mut self, v: Bytes) -> Self { - self.sig_b = v; + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; self } } -impl molecule::prelude::Builder for CloseBuilder { - type Entity = Close; - const NAME: &'static str = "CloseBuilder"; +impl molecule::prelude::Builder for FundBuilder { + type Entity = Fund; + const NAME: &'static str = "FundBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.state.as_slice().len() - + self.sig_a.as_slice().len() - + self.sig_b.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.state.as_slice().len(); - offsets.push(total_size); - total_size += self.sig_a.as_slice().len(); - offsets.push(total_size); - total_size += self.sig_b.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } - writer.write_all(self.state.as_slice())?; - writer.write_all(self.sig_a.as_slice())?; - writer.write_all(self.sig_b.as_slice())?; + writer.write_all(self.0[0].as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - Close::new_unchecked(inner.into()) + Fund::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for Fund { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for Fund { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: Fund) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for Fund { + fn from(value: [u8; 1usize]) -> Self { + FundReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for Fund { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: Fund) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: FundReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a FundReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a FundReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct ForceClose(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ForceClose { +pub struct Abort(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Abort { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5259,25 +6120,26 @@ impl ::core::fmt::LowerHex for ForceClose { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ForceClose { +impl ::core::fmt::Debug for Abort { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ForceClose { +impl ::core::fmt::Display for Abort { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl ::core::default::Default for ForceClose { +impl ::core::default::Default for Abort { fn default() -> Self { - let v: Vec = vec![0]; - ForceClose::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Abort::new_unchecked(v) } } -impl ForceClose { +impl Abort { + const DEFAULT_VALUE: [u8; 1] = [0]; pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -5287,15 +6149,15 @@ impl ForceClose { pub fn raw_data(&self) -> molecule::bytes::Bytes { self.as_bytes() } - pub fn as_reader<'r>(&'r self) -> ForceCloseReader<'r> { - ForceCloseReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> AbortReader<'r> { + AbortReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ForceClose { - type Builder = ForceCloseBuilder; - const NAME: &'static str = "ForceClose"; +impl molecule::prelude::Entity for Abort { + type Builder = AbortBuilder; + const NAME: &'static str = "Abort"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ForceClose(data) + Abort(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -5304,10 +6166,10 @@ impl molecule::prelude::Entity for ForceClose { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ForceCloseReader::from_slice(slice).map(|reader| reader.to_entity()) + AbortReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ForceCloseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + AbortReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() @@ -5317,8 +6179,8 @@ impl molecule::prelude::Entity for ForceClose { } } #[derive(Clone, Copy)] -pub struct ForceCloseReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ForceCloseReader<'r> { +pub struct AbortReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for AbortReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5327,19 +6189,19 @@ impl<'r> ::core::fmt::LowerHex for ForceCloseReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ForceCloseReader<'r> { +impl<'r> ::core::fmt::Debug for AbortReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ForceCloseReader<'r> { +impl<'r> ::core::fmt::Display for AbortReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; let raw_data = hex_string(&self.raw_data()); write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> ForceCloseReader<'r> { +impl<'r> AbortReader<'r> { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -5350,14 +6212,14 @@ impl<'r> ForceCloseReader<'r> { self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for ForceCloseReader<'r> { - type Entity = ForceClose; - const NAME: &'static str = "ForceCloseReader"; +impl<'r> molecule::prelude::Reader<'r> for AbortReader<'r> { + type Entity = Abort; + const NAME: &'static str = "AbortReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ForceCloseReader(slice) + AbortReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -5371,18 +6233,19 @@ impl<'r> molecule::prelude::Reader<'r> for ForceCloseReader<'r> { Ok(()) } } -pub struct ForceCloseBuilder(pub(crate) [Byte; 1]); -impl ::core::fmt::Debug for ForceCloseBuilder { +#[derive(Clone)] +pub struct AbortBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for AbortBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:?})", Self::NAME, &self.0[..]) } } -impl ::core::default::Default for ForceCloseBuilder { +impl ::core::default::Default for AbortBuilder { fn default() -> Self { - ForceCloseBuilder([Byte::default()]) + AbortBuilder([Byte::default()]) } } -impl ForceCloseBuilder { +impl AbortBuilder { pub const TOTAL_SIZE: usize = 1; pub const ITEM_SIZE: usize = 1; pub const ITEM_COUNT: usize = 1; @@ -5395,9 +6258,9 @@ impl ForceCloseBuilder { self } } -impl molecule::prelude::Builder for ForceCloseBuilder { - type Entity = ForceClose; - const NAME: &'static str = "ForceCloseBuilder"; +impl molecule::prelude::Builder for AbortBuilder { + type Entity = Abort; + const NAME: &'static str = "AbortBuilder"; fn expected_length(&self) -> usize { Self::TOTAL_SIZE } @@ -5409,12 +6272,60 @@ impl molecule::prelude::Builder for ForceCloseBuilder { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ForceClose::new_unchecked(inner.into()) + Abort::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for Abort { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for Abort { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: Abort) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for Abort { + fn from(value: [u8; 1usize]) -> Self { + AbortReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for Abort { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: Abort) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: AbortReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a AbortReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a AbortReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct ChannelWitness(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelWitness { +pub struct VCDispute(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for VCDispute { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5423,49 +6334,83 @@ impl ::core::fmt::LowerHex for ChannelWitness { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ChannelWitness { +impl ::core::fmt::Debug for VCDispute { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ChannelWitness { +impl ::core::fmt::Display for VCDispute { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}(", Self::NAME)?; - self.to_enum().display_inner(f)?; - write!(f, ")") + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; + write!(f, ", {}: {}", "parent_state_sigs", self.parent_state_sigs())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } } -impl ::core::default::Default for ChannelWitness { +impl ::core::default::Default for VCDispute { fn default() -> Self { - let v: Vec = vec![0, 0, 0, 0, 0]; - ChannelWitness::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + VCDispute::new_unchecked(v) } } -impl ChannelWitness { - pub const ITEMS_COUNT: usize = 5; - pub fn item_id(&self) -> molecule::Number { - molecule::unpack_number(self.as_slice()) +impl VCDispute { + const DEFAULT_VALUE: [u8; 44] = [ + 44, 0, 0, 0, 16, 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, + 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } - pub fn to_enum(&self) -> ChannelWitnessUnion { - let inner = self.0.slice(molecule::NUMBER_SIZE..); - match self.item_id() { - 0 => Fund::new_unchecked(inner).into(), - 1 => Abort::new_unchecked(inner).into(), - 2 => Dispute::new_unchecked(inner).into(), - 3 => Close::new_unchecked(inner).into(), - 4 => ForceClose::new_unchecked(inner).into(), - _ => panic!("{}: invalid data", Self::NAME), + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 } } - pub fn as_reader<'r>(&'r self) -> ChannelWitnessReader<'r> { - ChannelWitnessReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn sig_a(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } + pub fn sig_b(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } + pub fn parent_state_sigs(&self) -> Dispute { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + Dispute::new_unchecked(self.0.slice(start..end)) + } else { + Dispute::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> VCDisputeReader<'r> { + VCDisputeReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ChannelWitness { - type Builder = ChannelWitnessBuilder; - const NAME: &'static str = "ChannelWitness"; +impl molecule::prelude::Entity for VCDispute { + type Builder = VCDisputeBuilder; + const NAME: &'static str = "VCDispute"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelWitness(data) + VCDispute(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -5474,21 +6419,24 @@ impl molecule::prelude::Entity for ChannelWitness { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelWitnessReader::from_slice(slice).map(|reader| reader.to_entity()) + VCDisputeReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelWitnessReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + VCDisputeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().set(self.to_enum()) + Self::new_builder() + .sig_a(self.sig_a()) + .sig_b(self.sig_b()) + .parent_state_sigs(self.parent_state_sigs()) } } #[derive(Clone, Copy)] -pub struct ChannelWitnessReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelWitnessReader<'r> { +pub struct VCDisputeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for VCDisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5497,43 +6445,73 @@ impl<'r> ::core::fmt::LowerHex for ChannelWitnessReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelWitnessReader<'r> { +impl<'r> ::core::fmt::Debug for VCDisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelWitnessReader<'r> { +impl<'r> ::core::fmt::Display for VCDisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{}(", Self::NAME)?; - self.to_enum().display_inner(f)?; - write!(f, ")") - } -} -impl<'r> ChannelWitnessReader<'r> { - pub const ITEMS_COUNT: usize = 5; - pub fn item_id(&self) -> molecule::Number { - molecule::unpack_number(self.as_slice()) + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; + write!(f, ", {}: {}", "parent_state_sigs", self.parent_state_sigs())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") } - pub fn to_enum(&self) -> ChannelWitnessUnionReader<'r> { - let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; - match self.item_id() { - 0 => FundReader::new_unchecked(inner).into(), - 1 => AbortReader::new_unchecked(inner).into(), - 2 => DisputeReader::new_unchecked(inner).into(), - 3 => CloseReader::new_unchecked(inner).into(), - 4 => ForceCloseReader::new_unchecked(inner).into(), - _ => panic!("{}: invalid data", Self::NAME), +} +impl<'r> VCDisputeReader<'r> { + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn sig_a(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn sig_b(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn parent_state_sigs(&self) -> DisputeReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + DisputeReader::new_unchecked(&self.as_slice()[start..end]) + } else { + DisputeReader::new_unchecked(&self.as_slice()[start..]) } } } -impl<'r> molecule::prelude::Reader<'r> for ChannelWitnessReader<'r> { - type Entity = ChannelWitness; - const NAME: &'static str = "ChannelWitnessReader"; +impl<'r> molecule::prelude::Reader<'r> for VCDisputeReader<'r> { + type Entity = VCDispute; + const NAME: &'static str = "VCDisputeReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelWitnessReader(slice) + VCDisputeReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -5544,264 +6522,198 @@ impl<'r> molecule::prelude::Reader<'r> for ChannelWitnessReader<'r> { if slice_len < molecule::NUMBER_SIZE { return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); } - let item_id = molecule::unpack_number(slice); - let inner_slice = &slice[molecule::NUMBER_SIZE..]; - match item_id { - 0 => FundReader::verify(inner_slice, compatible), - 1 => AbortReader::verify(inner_slice, compatible), - 2 => DisputeReader::verify(inner_slice, compatible), - 3 => CloseReader::verify(inner_slice, compatible), - 4 => ForceCloseReader::verify(inner_slice, compatible), - _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), - }?; + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + DisputeReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ChannelWitnessBuilder(pub(crate) ChannelWitnessUnion); -impl ChannelWitnessBuilder { - pub const ITEMS_COUNT: usize = 5; - pub fn set(mut self, v: I) -> Self - where - I: ::core::convert::Into, - { - self.0 = v.into(); +#[derive(Clone, Debug, Default)] +pub struct VCDisputeBuilder { + pub(crate) sig_a: Bytes, + pub(crate) sig_b: Bytes, + pub(crate) parent_state_sigs: Dispute, +} +impl VCDisputeBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn sig_a(mut self, v: Bytes) -> Self { + self.sig_a = v; + self + } + pub fn sig_b(mut self, v: Bytes) -> Self { + self.sig_b = v; + self + } + pub fn parent_state_sigs(mut self, v: Dispute) -> Self { + self.parent_state_sigs = v; self } } -impl molecule::prelude::Builder for ChannelWitnessBuilder { - type Entity = ChannelWitness; - const NAME: &'static str = "ChannelWitnessBuilder"; +impl molecule::prelude::Builder for VCDisputeBuilder { + type Entity = VCDispute; + const NAME: &'static str = "VCDisputeBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE + self.0.as_slice().len() + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.sig_a.as_slice().len() + + self.sig_b.as_slice().len() + + self.parent_state_sigs.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(&molecule::pack_number(self.0.item_id()))?; - writer.write_all(self.0.as_slice()) + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.sig_a.as_slice().len(); + offsets.push(total_size); + total_size += self.sig_b.as_slice().len(); + offsets.push(total_size); + total_size += self.parent_state_sigs.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.sig_a.as_slice())?; + writer.write_all(self.sig_b.as_slice())?; + writer.write_all(self.parent_state_sigs.as_slice())?; + Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelWitness::new_unchecked(inner.into()) - } -} -#[derive(Debug, Clone)] -pub enum ChannelWitnessUnion { - Fund(Fund), - Abort(Abort), - Dispute(Dispute), - Close(Close), - ForceClose(ForceClose), -} -#[derive(Debug, Clone, Copy)] -pub enum ChannelWitnessUnionReader<'r> { - Fund(FundReader<'r>), - Abort(AbortReader<'r>), - Dispute(DisputeReader<'r>), - Close(CloseReader<'r>), - ForceClose(ForceCloseReader<'r>), -} -impl ::core::default::Default for ChannelWitnessUnion { - fn default() -> Self { - ChannelWitnessUnion::Fund(::core::default::Default::default()) + VCDispute::new_unchecked(inner.into()) } } -impl ::core::fmt::Display for ChannelWitnessUnion { +#[derive(Clone)] +pub struct Dispute(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Dispute { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - ChannelWitnessUnion::Fund(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Fund::NAME, item) - } - ChannelWitnessUnion::Abort(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Abort::NAME, item) - } - ChannelWitnessUnion::Dispute(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Dispute::NAME, item) - } - ChannelWitnessUnion::Close(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Close::NAME, item) - } - ChannelWitnessUnion::ForceClose(ref item) => { - write!(f, "{}::{}({})", Self::NAME, ForceClose::NAME, item) - } + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; } + write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Display for ChannelWitnessUnionReader<'r> { +impl ::core::fmt::Debug for Dispute { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - ChannelWitnessUnionReader::Fund(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Fund::NAME, item) - } - ChannelWitnessUnionReader::Abort(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Abort::NAME, item) - } - ChannelWitnessUnionReader::Dispute(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Dispute::NAME, item) - } - ChannelWitnessUnionReader::Close(ref item) => { - write!(f, "{}::{}({})", Self::NAME, Close::NAME, item) - } - ChannelWitnessUnionReader::ForceClose(ref item) => { - write!(f, "{}::{}({})", Self::NAME, ForceClose::NAME, item) - } - } + write!(f, "{}({:#x})", Self::NAME, self) } } -impl ChannelWitnessUnion { - pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - ChannelWitnessUnion::Fund(ref item) => write!(f, "{}", item), - ChannelWitnessUnion::Abort(ref item) => write!(f, "{}", item), - ChannelWitnessUnion::Dispute(ref item) => write!(f, "{}", item), - ChannelWitnessUnion::Close(ref item) => write!(f, "{}", item), - ChannelWitnessUnion::ForceClose(ref item) => write!(f, "{}", item), +impl ::core::fmt::Display for Dispute { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; } + write!(f, " }}") } } -impl<'r> ChannelWitnessUnionReader<'r> { - pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - ChannelWitnessUnionReader::Fund(ref item) => write!(f, "{}", item), - ChannelWitnessUnionReader::Abort(ref item) => write!(f, "{}", item), - ChannelWitnessUnionReader::Dispute(ref item) => write!(f, "{}", item), - ChannelWitnessUnionReader::Close(ref item) => write!(f, "{}", item), - ChannelWitnessUnionReader::ForceClose(ref item) => write!(f, "{}", item), - } +impl ::core::default::Default for Dispute { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Dispute::new_unchecked(v) } } -impl ::core::convert::From for ChannelWitnessUnion { - fn from(item: Fund) -> Self { - ChannelWitnessUnion::Fund(item) +impl Dispute { + const DEFAULT_VALUE: [u8; 20] = [ + 20, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } -} -impl ::core::convert::From for ChannelWitnessUnion { - fn from(item: Abort) -> Self { - ChannelWitnessUnion::Abort(item) + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } -} -impl ::core::convert::From for ChannelWitnessUnion { - fn from(item: Dispute) -> Self { - ChannelWitnessUnion::Dispute(item) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT } -} -impl ::core::convert::From for ChannelWitnessUnion { - fn from(item: Close) -> Self { - ChannelWitnessUnion::Close(item) - } -} -impl ::core::convert::From for ChannelWitnessUnion { - fn from(item: ForceClose) -> Self { - ChannelWitnessUnion::ForceClose(item) - } -} -impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { - fn from(item: FundReader<'r>) -> Self { - ChannelWitnessUnionReader::Fund(item) - } -} -impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { - fn from(item: AbortReader<'r>) -> Self { - ChannelWitnessUnionReader::Abort(item) + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() } -} -impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { - fn from(item: DisputeReader<'r>) -> Self { - ChannelWitnessUnionReader::Dispute(item) + pub fn sig_a(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) } -} -impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { - fn from(item: CloseReader<'r>) -> Self { - ChannelWitnessUnionReader::Close(item) + pub fn sig_b(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } } -} -impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { - fn from(item: ForceCloseReader<'r>) -> Self { - ChannelWitnessUnionReader::ForceClose(item) + pub fn as_reader<'r>(&'r self) -> DisputeReader<'r> { + DisputeReader::new_unchecked(self.as_slice()) } } -impl ChannelWitnessUnion { - pub const NAME: &'static str = "ChannelWitnessUnion"; - pub fn as_bytes(&self) -> molecule::bytes::Bytes { - match self { - ChannelWitnessUnion::Fund(item) => item.as_bytes(), - ChannelWitnessUnion::Abort(item) => item.as_bytes(), - ChannelWitnessUnion::Dispute(item) => item.as_bytes(), - ChannelWitnessUnion::Close(item) => item.as_bytes(), - ChannelWitnessUnion::ForceClose(item) => item.as_bytes(), - } - } - pub fn as_slice(&self) -> &[u8] { - match self { - ChannelWitnessUnion::Fund(item) => item.as_slice(), - ChannelWitnessUnion::Abort(item) => item.as_slice(), - ChannelWitnessUnion::Dispute(item) => item.as_slice(), - ChannelWitnessUnion::Close(item) => item.as_slice(), - ChannelWitnessUnion::ForceClose(item) => item.as_slice(), - } +impl molecule::prelude::Entity for Dispute { + type Builder = DisputeBuilder; + const NAME: &'static str = "Dispute"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Dispute(data) } - pub fn item_id(&self) -> molecule::Number { - match self { - ChannelWitnessUnion::Fund(_) => 0, - ChannelWitnessUnion::Abort(_) => 1, - ChannelWitnessUnion::Dispute(_) => 2, - ChannelWitnessUnion::Close(_) => 3, - ChannelWitnessUnion::ForceClose(_) => 4, - } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() } - pub fn item_name(&self) -> &str { - match self { - ChannelWitnessUnion::Fund(_) => "Fund", - ChannelWitnessUnion::Abort(_) => "Abort", - ChannelWitnessUnion::Dispute(_) => "Dispute", - ChannelWitnessUnion::Close(_) => "Close", - ChannelWitnessUnion::ForceClose(_) => "ForceClose", - } + fn as_slice(&self) -> &[u8] { + &self.0[..] } - pub fn as_reader<'r>(&'r self) -> ChannelWitnessUnionReader<'r> { - match self { - ChannelWitnessUnion::Fund(item) => item.as_reader().into(), - ChannelWitnessUnion::Abort(item) => item.as_reader().into(), - ChannelWitnessUnion::Dispute(item) => item.as_reader().into(), - ChannelWitnessUnion::Close(item) => item.as_reader().into(), - ChannelWitnessUnion::ForceClose(item) => item.as_reader().into(), - } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DisputeReader::from_slice(slice).map(|reader| reader.to_entity()) } -} -impl<'r> ChannelWitnessUnionReader<'r> { - pub const NAME: &'r str = "ChannelWitnessUnionReader"; - pub fn as_slice(&self) -> &'r [u8] { - match self { - ChannelWitnessUnionReader::Fund(item) => item.as_slice(), - ChannelWitnessUnionReader::Abort(item) => item.as_slice(), - ChannelWitnessUnionReader::Dispute(item) => item.as_slice(), - ChannelWitnessUnionReader::Close(item) => item.as_slice(), - ChannelWitnessUnionReader::ForceClose(item) => item.as_slice(), - } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DisputeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } - pub fn item_id(&self) -> molecule::Number { - match self { - ChannelWitnessUnionReader::Fund(_) => 0, - ChannelWitnessUnionReader::Abort(_) => 1, - ChannelWitnessUnionReader::Dispute(_) => 2, - ChannelWitnessUnionReader::Close(_) => 3, - ChannelWitnessUnionReader::ForceClose(_) => 4, - } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() } - pub fn item_name(&self) -> &str { - match self { - ChannelWitnessUnionReader::Fund(_) => "Fund", - ChannelWitnessUnionReader::Abort(_) => "Abort", - ChannelWitnessUnionReader::Dispute(_) => "Dispute", - ChannelWitnessUnionReader::Close(_) => "Close", - ChannelWitnessUnionReader::ForceClose(_) => "ForceClose", - } + fn as_builder(self) -> Self::Builder { + Self::new_builder().sig_a(self.sig_a()).sig_b(self.sig_b()) } } -#[derive(Clone)] -pub struct ChannelState(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelState { +#[derive(Clone, Copy)] +pub struct DisputeReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for DisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5810,18 +6722,16 @@ impl ::core::fmt::LowerHex for ChannelState { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ChannelState { +impl<'r> ::core::fmt::Debug for DisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ChannelState { +impl<'r> ::core::fmt::Display for DisputeReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "balances", self.balances())?; - write!(f, ", {}: {}", "version", self.version())?; - write!(f, ", {}: {}", "is_final", self.is_final())?; + write!(f, "{}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -5829,19 +6739,8 @@ impl ::core::fmt::Display for ChannelState { write!(f, " }}") } } -impl ::core::default::Default for ChannelState { - fn default() -> Self { - let v: Vec = vec![ - 97, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 84, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, - 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - ChannelState::new_unchecked(v.into()) - } -} -impl ChannelState { - pub const FIELD_COUNT: usize = 4; +impl<'r> DisputeReader<'r> { + pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -5858,43 +6757,2280 @@ impl ChannelState { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn channel_id(&self) -> Byte32 { + pub fn sig_a(&self) -> BytesReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32::new_unchecked(self.0.slice(start..end)) + BytesReader::new_unchecked(&self.as_slice()[start..end]) } - pub fn balances(&self) -> Balances { + pub fn sig_b(&self) -> BytesReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Balances::new_unchecked(self.0.slice(start..end)) + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for DisputeReader<'r> { + type Entity = Dispute; + const NAME: &'static str = "DisputeReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + DisputeReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct DisputeBuilder { + pub(crate) sig_a: Bytes, + pub(crate) sig_b: Bytes, +} +impl DisputeBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn sig_a(mut self, v: Bytes) -> Self { + self.sig_a = v; + self + } + pub fn sig_b(mut self, v: Bytes) -> Self { + self.sig_b = v; + self + } +} +impl molecule::prelude::Builder for DisputeBuilder { + type Entity = Dispute; + const NAME: &'static str = "DisputeBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.sig_a.as_slice().len() + + self.sig_b.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.sig_a.as_slice().len(); + offsets.push(total_size); + total_size += self.sig_b.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.sig_a.as_slice())?; + writer.write_all(self.sig_b.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Dispute::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct Close(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Close { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Close { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Close { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "state", self.state())?; + write!(f, ", {}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Close { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Close::new_unchecked(v) + } +} +impl Close { + const DEFAULT_VALUE: [u8; 129] = [ + 129, 0, 0, 0, 16, 0, 0, 0, 121, 0, 0, 0, 125, 0, 0, 0, 105, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, + 0, 92, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn state(&self) -> ChannelState { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelState::new_unchecked(self.0.slice(start..end)) + } + pub fn sig_a(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } + pub fn sig_b(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } else { + Bytes::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> CloseReader<'r> { + CloseReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Close { + type Builder = CloseBuilder; + const NAME: &'static str = "Close"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Close(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + CloseReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + CloseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .state(self.state()) + .sig_a(self.sig_a()) + .sig_b(self.sig_b()) + } +} +#[derive(Clone, Copy)] +pub struct CloseReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for CloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for CloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for CloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "state", self.state())?; + write!(f, ", {}: {}", "sig_a", self.sig_a())?; + write!(f, ", {}: {}", "sig_b", self.sig_b())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> CloseReader<'r> { + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn state(&self) -> ChannelStateReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelStateReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn sig_a(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn sig_b(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BytesReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for CloseReader<'r> { + type Entity = Close; + const NAME: &'static str = "CloseReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + CloseReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BytesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct CloseBuilder { + pub(crate) state: ChannelState, + pub(crate) sig_a: Bytes, + pub(crate) sig_b: Bytes, +} +impl CloseBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn state(mut self, v: ChannelState) -> Self { + self.state = v; + self + } + pub fn sig_a(mut self, v: Bytes) -> Self { + self.sig_a = v; + self + } + pub fn sig_b(mut self, v: Bytes) -> Self { + self.sig_b = v; + self + } +} +impl molecule::prelude::Builder for CloseBuilder { + type Entity = Close; + const NAME: &'static str = "CloseBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.state.as_slice().len() + + self.sig_a.as_slice().len() + + self.sig_b.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.state.as_slice().len(); + offsets.push(total_size); + total_size += self.sig_a.as_slice().len(); + offsets.push(total_size); + total_size += self.sig_b.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.state.as_slice())?; + writer.write_all(self.sig_a.as_slice())?; + writer.write_all(self.sig_b.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Close::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ForceClose(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ForceClose { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ForceClose { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ForceClose { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for ForceClose { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ForceClose::new_unchecked(v) + } +} +impl ForceClose { + const DEFAULT_VALUE: [u8; 1] = [0]; + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> ForceCloseReader<'r> { + ForceCloseReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ForceClose { + type Builder = ForceCloseBuilder; + const NAME: &'static str = "ForceClose"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ForceClose(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ForceCloseReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ForceCloseReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set([self.nth0()]) + } +} +#[derive(Clone, Copy)] +pub struct ForceCloseReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ForceCloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ForceCloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ForceCloseReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl<'r> ForceCloseReader<'r> { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +impl<'r> molecule::prelude::Reader<'r> for ForceCloseReader<'r> { + type Entity = ForceClose; + const NAME: &'static str = "ForceCloseReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ForceCloseReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +#[derive(Clone)] +pub struct ForceCloseBuilder(pub(crate) [Byte; 1]); +impl ::core::fmt::Debug for ForceCloseBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for ForceCloseBuilder { + fn default() -> Self { + ForceCloseBuilder([Byte::default()]) + } +} +impl ForceCloseBuilder { + pub const TOTAL_SIZE: usize = 1; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 1; + pub fn set(mut self, v: [Byte; 1]) -> Self { + self.0 = v; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for ForceCloseBuilder { + type Entity = ForceClose; + const NAME: &'static str = "ForceCloseBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.0[0].as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ForceClose::new_unchecked(inner.into()) + } +} +impl From<[Byte; 1usize]> for ForceClose { + fn from(value: [Byte; 1usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for ForceClose { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 1usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 1usize] { + #[track_caller] + fn from(value: ForceClose) -> Self { + [value.nth0()] + } +} +impl From<[u8; 1usize]> for ForceClose { + fn from(value: [u8; 1usize]) -> Self { + ForceCloseReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for ForceClose { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 1usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 1usize] { + #[track_caller] + fn from(value: ForceClose) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: ForceCloseReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a ForceCloseReader<'a>> for &'a [u8; 1usize] { + #[track_caller] + fn from(value: &'a ForceCloseReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +#[derive(Clone)] +pub struct ChannelWitness(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelWitness { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ChannelWitness { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ChannelWitness { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl ::core::default::Default for ChannelWitness { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelWitness::new_unchecked(v) + } +} +impl ChannelWitness { + const DEFAULT_VALUE: [u8; 5] = [0, 0, 0, 0, 0]; + pub const ITEMS_COUNT: usize = 6; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> ChannelWitnessUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 0 => Fund::new_unchecked(inner).into(), + 1 => Abort::new_unchecked(inner).into(), + 2 => Dispute::new_unchecked(inner).into(), + 3 => VCDispute::new_unchecked(inner).into(), + 4 => Close::new_unchecked(inner).into(), + 5 => ForceClose::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } + pub fn as_reader<'r>(&'r self) -> ChannelWitnessReader<'r> { + ChannelWitnessReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ChannelWitness { + type Builder = ChannelWitnessBuilder; + const NAME: &'static str = "ChannelWitness"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelWitness(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelWitnessReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelWitnessReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_enum()) + } +} +#[derive(Clone, Copy)] +pub struct ChannelWitnessReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelWitnessReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ChannelWitnessReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ChannelWitnessReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl<'r> ChannelWitnessReader<'r> { + pub const ITEMS_COUNT: usize = 6; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> ChannelWitnessUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 0 => FundReader::new_unchecked(inner).into(), + 1 => AbortReader::new_unchecked(inner).into(), + 2 => DisputeReader::new_unchecked(inner).into(), + 3 => VCDisputeReader::new_unchecked(inner).into(), + 4 => CloseReader::new_unchecked(inner).into(), + 5 => ForceCloseReader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ChannelWitnessReader<'r> { + type Entity = ChannelWitness; + const NAME: &'static str = "ChannelWitnessReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ChannelWitnessReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 0 => FundReader::verify(inner_slice, compatible), + 1 => AbortReader::verify(inner_slice, compatible), + 2 => DisputeReader::verify(inner_slice, compatible), + 3 => VCDisputeReader::verify(inner_slice, compatible), + 4 => CloseReader::verify(inner_slice, compatible), + 5 => ForceCloseReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ChannelWitnessBuilder(pub(crate) ChannelWitnessUnion); +impl ChannelWitnessBuilder { + pub const ITEMS_COUNT: usize = 6; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); + self + } +} +impl molecule::prelude::Builder for ChannelWitnessBuilder { + type Entity = ChannelWitness; + const NAME: &'static str = "ChannelWitnessBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + self.0.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ChannelWitness::new_unchecked(inner.into()) + } +} +#[derive(Debug, Clone)] +pub enum ChannelWitnessUnion { + Fund(Fund), + Abort(Abort), + Dispute(Dispute), + VCDispute(VCDispute), + Close(Close), + ForceClose(ForceClose), +} +#[derive(Debug, Clone, Copy)] +pub enum ChannelWitnessUnionReader<'r> { + Fund(FundReader<'r>), + Abort(AbortReader<'r>), + Dispute(DisputeReader<'r>), + VCDispute(VCDisputeReader<'r>), + Close(CloseReader<'r>), + ForceClose(ForceCloseReader<'r>), +} +impl ::core::default::Default for ChannelWitnessUnion { + fn default() -> Self { + ChannelWitnessUnion::Fund(::core::default::Default::default()) + } +} +impl ::core::fmt::Display for ChannelWitnessUnion { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + ChannelWitnessUnion::Fund(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Fund::NAME, item) + } + ChannelWitnessUnion::Abort(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Abort::NAME, item) + } + ChannelWitnessUnion::Dispute(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Dispute::NAME, item) + } + ChannelWitnessUnion::VCDispute(ref item) => { + write!(f, "{}::{}({})", Self::NAME, VCDispute::NAME, item) + } + ChannelWitnessUnion::Close(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Close::NAME, item) + } + ChannelWitnessUnion::ForceClose(ref item) => { + write!(f, "{}::{}({})", Self::NAME, ForceClose::NAME, item) + } + } + } +} +impl<'r> ::core::fmt::Display for ChannelWitnessUnionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + ChannelWitnessUnionReader::Fund(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Fund::NAME, item) + } + ChannelWitnessUnionReader::Abort(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Abort::NAME, item) + } + ChannelWitnessUnionReader::Dispute(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Dispute::NAME, item) + } + ChannelWitnessUnionReader::VCDispute(ref item) => { + write!(f, "{}::{}({})", Self::NAME, VCDispute::NAME, item) + } + ChannelWitnessUnionReader::Close(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Close::NAME, item) + } + ChannelWitnessUnionReader::ForceClose(ref item) => { + write!(f, "{}::{}({})", Self::NAME, ForceClose::NAME, item) + } + } + } +} +impl ChannelWitnessUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + ChannelWitnessUnion::Fund(ref item) => write!(f, "{}", item), + ChannelWitnessUnion::Abort(ref item) => write!(f, "{}", item), + ChannelWitnessUnion::Dispute(ref item) => write!(f, "{}", item), + ChannelWitnessUnion::VCDispute(ref item) => write!(f, "{}", item), + ChannelWitnessUnion::Close(ref item) => write!(f, "{}", item), + ChannelWitnessUnion::ForceClose(ref item) => write!(f, "{}", item), + } + } +} +impl<'r> ChannelWitnessUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + ChannelWitnessUnionReader::Fund(ref item) => write!(f, "{}", item), + ChannelWitnessUnionReader::Abort(ref item) => write!(f, "{}", item), + ChannelWitnessUnionReader::Dispute(ref item) => write!(f, "{}", item), + ChannelWitnessUnionReader::VCDispute(ref item) => write!(f, "{}", item), + ChannelWitnessUnionReader::Close(ref item) => write!(f, "{}", item), + ChannelWitnessUnionReader::ForceClose(ref item) => write!(f, "{}", item), + } + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: Fund) -> Self { + ChannelWitnessUnion::Fund(item) + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: Abort) -> Self { + ChannelWitnessUnion::Abort(item) + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: Dispute) -> Self { + ChannelWitnessUnion::Dispute(item) + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: VCDispute) -> Self { + ChannelWitnessUnion::VCDispute(item) + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: Close) -> Self { + ChannelWitnessUnion::Close(item) + } +} +impl ::core::convert::From for ChannelWitnessUnion { + fn from(item: ForceClose) -> Self { + ChannelWitnessUnion::ForceClose(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: FundReader<'r>) -> Self { + ChannelWitnessUnionReader::Fund(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: AbortReader<'r>) -> Self { + ChannelWitnessUnionReader::Abort(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: DisputeReader<'r>) -> Self { + ChannelWitnessUnionReader::Dispute(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: VCDisputeReader<'r>) -> Self { + ChannelWitnessUnionReader::VCDispute(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: CloseReader<'r>) -> Self { + ChannelWitnessUnionReader::Close(item) + } +} +impl<'r> ::core::convert::From> for ChannelWitnessUnionReader<'r> { + fn from(item: ForceCloseReader<'r>) -> Self { + ChannelWitnessUnionReader::ForceClose(item) + } +} +impl ChannelWitnessUnion { + pub const NAME: &'static str = "ChannelWitnessUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + ChannelWitnessUnion::Fund(item) => item.as_bytes(), + ChannelWitnessUnion::Abort(item) => item.as_bytes(), + ChannelWitnessUnion::Dispute(item) => item.as_bytes(), + ChannelWitnessUnion::VCDispute(item) => item.as_bytes(), + ChannelWitnessUnion::Close(item) => item.as_bytes(), + ChannelWitnessUnion::ForceClose(item) => item.as_bytes(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + ChannelWitnessUnion::Fund(item) => item.as_slice(), + ChannelWitnessUnion::Abort(item) => item.as_slice(), + ChannelWitnessUnion::Dispute(item) => item.as_slice(), + ChannelWitnessUnion::VCDispute(item) => item.as_slice(), + ChannelWitnessUnion::Close(item) => item.as_slice(), + ChannelWitnessUnion::ForceClose(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + ChannelWitnessUnion::Fund(_) => 0, + ChannelWitnessUnion::Abort(_) => 1, + ChannelWitnessUnion::Dispute(_) => 2, + ChannelWitnessUnion::VCDispute(_) => 3, + ChannelWitnessUnion::Close(_) => 4, + ChannelWitnessUnion::ForceClose(_) => 5, + } + } + pub fn item_name(&self) -> &str { + match self { + ChannelWitnessUnion::Fund(_) => "Fund", + ChannelWitnessUnion::Abort(_) => "Abort", + ChannelWitnessUnion::Dispute(_) => "Dispute", + ChannelWitnessUnion::VCDispute(_) => "VCDispute", + ChannelWitnessUnion::Close(_) => "Close", + ChannelWitnessUnion::ForceClose(_) => "ForceClose", + } + } + pub fn as_reader<'r>(&'r self) -> ChannelWitnessUnionReader<'r> { + match self { + ChannelWitnessUnion::Fund(item) => item.as_reader().into(), + ChannelWitnessUnion::Abort(item) => item.as_reader().into(), + ChannelWitnessUnion::Dispute(item) => item.as_reader().into(), + ChannelWitnessUnion::VCDispute(item) => item.as_reader().into(), + ChannelWitnessUnion::Close(item) => item.as_reader().into(), + ChannelWitnessUnion::ForceClose(item) => item.as_reader().into(), + } + } +} +impl<'r> ChannelWitnessUnionReader<'r> { + pub const NAME: &'r str = "ChannelWitnessUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + ChannelWitnessUnionReader::Fund(item) => item.as_slice(), + ChannelWitnessUnionReader::Abort(item) => item.as_slice(), + ChannelWitnessUnionReader::Dispute(item) => item.as_slice(), + ChannelWitnessUnionReader::VCDispute(item) => item.as_slice(), + ChannelWitnessUnionReader::Close(item) => item.as_slice(), + ChannelWitnessUnionReader::ForceClose(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + ChannelWitnessUnionReader::Fund(_) => 0, + ChannelWitnessUnionReader::Abort(_) => 1, + ChannelWitnessUnionReader::Dispute(_) => 2, + ChannelWitnessUnionReader::VCDispute(_) => 3, + ChannelWitnessUnionReader::Close(_) => 4, + ChannelWitnessUnionReader::ForceClose(_) => 5, + } + } + pub fn item_name(&self) -> &str { + match self { + ChannelWitnessUnionReader::Fund(_) => "Fund", + ChannelWitnessUnionReader::Abort(_) => "Abort", + ChannelWitnessUnionReader::Dispute(_) => "Dispute", + ChannelWitnessUnionReader::VCDispute(_) => "VCDispute", + ChannelWitnessUnionReader::Close(_) => "Close", + ChannelWitnessUnionReader::ForceClose(_) => "ForceClose", + } + } +} +impl From for ChannelWitness { + fn from(value: Fund) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for ChannelWitness { + fn from(value: Abort) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for ChannelWitness { + fn from(value: Dispute) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for ChannelWitness { + fn from(value: VCDispute) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for ChannelWitness { + fn from(value: Close) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for ChannelWitness { + fn from(value: ForceClose) -> Self { + Self::new_builder().set(value).build() + } +} +#[derive(Clone)] +pub struct ChannelState(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelState { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ChannelState { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ChannelState { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "channel_id", self.channel_id())?; + write!(f, ", {}: {}", "balances", self.balances())?; + write!(f, ", {}: {}", "version", self.version())?; + write!(f, ", {}: {}", "is_final", self.is_final())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for ChannelState { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelState::new_unchecked(v) + } +} +impl ChannelState { + const DEFAULT_VALUE: [u8; 105] = [ + 105, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 92, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 16, 0, + 0, 0, 32, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn channel_id(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn balances(&self) -> Balances { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Balances::new_unchecked(self.0.slice(start..end)) + } + pub fn version(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } + pub fn is_final(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } else { + Bool::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ChannelStateReader<'r> { + ChannelStateReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ChannelState { + type Builder = ChannelStateBuilder; + const NAME: &'static str = "ChannelState"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelState(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelStateReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelStateReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .channel_id(self.channel_id()) + .balances(self.balances()) + .version(self.version()) + .is_final(self.is_final()) + } +} +#[derive(Clone, Copy)] +pub struct ChannelStateReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelStateReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ChannelStateReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ChannelStateReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "channel_id", self.channel_id())?; + write!(f, ", {}: {}", "balances", self.balances())?; + write!(f, ", {}: {}", "version", self.version())?; + write!(f, ", {}: {}", "is_final", self.is_final())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> ChannelStateReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn channel_id(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn balances(&self) -> BalancesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + BalancesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn version(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn is_final(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } else { + BoolReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ChannelStateReader<'r> { + type Entity = ChannelState; + const NAME: &'static str = "ChannelStateReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ChannelStateReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BalancesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Uint64Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + BoolReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ChannelStateBuilder { + pub(crate) channel_id: Byte32, + pub(crate) balances: Balances, + pub(crate) version: Uint64, + pub(crate) is_final: Bool, +} +impl ChannelStateBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn channel_id(mut self, v: Byte32) -> Self { + self.channel_id = v; + self + } + pub fn balances(mut self, v: Balances) -> Self { + self.balances = v; + self + } + pub fn version(mut self, v: Uint64) -> Self { + self.version = v; + self + } + pub fn is_final(mut self, v: Bool) -> Self { + self.is_final = v; + self + } +} +impl molecule::prelude::Builder for ChannelStateBuilder { + type Entity = ChannelState; + const NAME: &'static str = "ChannelStateBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.channel_id.as_slice().len() + + self.balances.as_slice().len() + + self.version.as_slice().len() + + self.is_final.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.channel_id.as_slice().len(); + offsets.push(total_size); + total_size += self.balances.as_slice().len(); + offsets.push(total_size); + total_size += self.version.as_slice().len(); + offsets.push(total_size); + total_size += self.is_final.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.channel_id.as_slice())?; + writer.write_all(self.balances.as_slice())?; + writer.write_all(self.version.as_slice())?; + writer.write_all(self.is_final.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ChannelState::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ChannelStatus(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelStatus { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ChannelStatus { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ChannelStatus { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "state", self.state())?; + write!(f, ", {}: {}", "funded", self.funded())?; + write!(f, ", {}: {}", "disputed", self.disputed())?; + write!(f, ", {}: {}", "vc_disputed", self.vc_disputed())?; + write!(f, ", {}: {}", "vcts_hash", self.vcts_hash())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for ChannelStatus { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelStatus::new_unchecked(v) + } +} +impl ChannelStatus { + const DEFAULT_VALUE: [u8; 176] = [ + 176, 0, 0, 0, 24, 0, 0, 0, 129, 0, 0, 0, 134, 0, 0, 0, 139, 0, 0, 0, 144, 0, 0, 0, 105, 0, + 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 92, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 16, 0, 0, 0, + 32, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn state(&self) -> ChannelState { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelState::new_unchecked(self.0.slice(start..end)) + } + pub fn funded(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } + pub fn disputed(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } + pub fn vc_disputed(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } + pub fn vcts_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } else { + Byte32::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> ChannelStatusReader<'r> { + ChannelStatusReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ChannelStatus { + type Builder = ChannelStatusBuilder; + const NAME: &'static str = "ChannelStatus"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelStatus(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelStatusReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelStatusReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .state(self.state()) + .funded(self.funded()) + .disputed(self.disputed()) + .vc_disputed(self.vc_disputed()) + .vcts_hash(self.vcts_hash()) + } +} +#[derive(Clone, Copy)] +pub struct ChannelStatusReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelStatusReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ChannelStatusReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ChannelStatusReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "state", self.state())?; + write!(f, ", {}: {}", "funded", self.funded())?; + write!(f, ", {}: {}", "disputed", self.disputed())?; + write!(f, ", {}: {}", "vc_disputed", self.vc_disputed())?; + write!(f, ", {}: {}", "vcts_hash", self.vcts_hash())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> ChannelStatusReader<'r> { + pub const FIELD_COUNT: usize = 5; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn state(&self) -> ChannelStateReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelStateReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn funded(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn disputed(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn vc_disputed(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn vcts_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } else { + Byte32Reader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ChannelStatusReader<'r> { + type Entity = ChannelStatus; + const NAME: &'static str = "ChannelStatusReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ChannelStatusReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BoolReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BoolReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + BoolReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Byte32Reader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ChannelStatusBuilder { + pub(crate) state: ChannelState, + pub(crate) funded: Bool, + pub(crate) disputed: Bool, + pub(crate) vc_disputed: Bool, + pub(crate) vcts_hash: Byte32, +} +impl ChannelStatusBuilder { + pub const FIELD_COUNT: usize = 5; + pub fn state(mut self, v: ChannelState) -> Self { + self.state = v; + self + } + pub fn funded(mut self, v: Bool) -> Self { + self.funded = v; + self + } + pub fn disputed(mut self, v: Bool) -> Self { + self.disputed = v; + self + } + pub fn vc_disputed(mut self, v: Bool) -> Self { + self.vc_disputed = v; + self + } + pub fn vcts_hash(mut self, v: Byte32) -> Self { + self.vcts_hash = v; + self + } +} +impl molecule::prelude::Builder for ChannelStatusBuilder { + type Entity = ChannelStatus; + const NAME: &'static str = "ChannelStatusBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.state.as_slice().len() + + self.funded.as_slice().len() + + self.disputed.as_slice().len() + + self.vc_disputed.as_slice().len() + + self.vcts_hash.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.state.as_slice().len(); + offsets.push(total_size); + total_size += self.funded.as_slice().len(); + offsets.push(total_size); + total_size += self.disputed.as_slice().len(); + offsets.push(total_size); + total_size += self.vc_disputed.as_slice().len(); + offsets.push(total_size); + total_size += self.vcts_hash.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.state.as_slice())?; + writer.write_all(self.funded.as_slice())?; + writer.write_all(self.disputed.as_slice())?; + writer.write_all(self.vc_disputed.as_slice())?; + writer.write_all(self.vcts_hash.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ChannelStatus::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ChannelToken(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ChannelToken { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ChannelToken { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ChannelToken { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "out_point", self.out_point())?; + write!(f, " }}") + } +} +impl ::core::default::Default for ChannelToken { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ChannelToken::new_unchecked(v) + } +} +impl ChannelToken { + const DEFAULT_VALUE: [u8; 36] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ]; + pub const TOTAL_SIZE: usize = 36; + pub const FIELD_SIZES: [usize; 1] = [36]; + pub const FIELD_COUNT: usize = 1; + pub fn out_point(&self) -> OutPoint { + OutPoint::new_unchecked(self.0.slice(0..36)) + } + pub fn as_reader<'r>(&'r self) -> ChannelTokenReader<'r> { + ChannelTokenReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ChannelToken { + type Builder = ChannelTokenBuilder; + const NAME: &'static str = "ChannelToken"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelToken(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelTokenReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ChannelTokenReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().out_point(self.out_point()) + } +} +#[derive(Clone, Copy)] +pub struct ChannelTokenReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ChannelTokenReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ChannelTokenReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ChannelTokenReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "out_point", self.out_point())?; + write!(f, " }}") + } +} +impl<'r> ChannelTokenReader<'r> { + pub const TOTAL_SIZE: usize = 36; + pub const FIELD_SIZES: [usize; 1] = [36]; + pub const FIELD_COUNT: usize = 1; + pub fn out_point(&self) -> OutPointReader<'r> { + OutPointReader::new_unchecked(&self.as_slice()[0..36]) + } +} +impl<'r> molecule::prelude::Reader<'r> for ChannelTokenReader<'r> { + type Entity = ChannelToken; + const NAME: &'static str = "ChannelTokenReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ChannelTokenReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ChannelTokenBuilder { + pub(crate) out_point: OutPoint, +} +impl ChannelTokenBuilder { + pub const TOTAL_SIZE: usize = 36; + pub const FIELD_SIZES: [usize; 1] = [36]; + pub const FIELD_COUNT: usize = 1; + pub fn out_point(mut self, v: OutPoint) -> Self { + self.out_point = v; + self + } +} +impl molecule::prelude::Builder for ChannelTokenBuilder { + type Entity = ChannelToken; + const NAME: &'static str = "ChannelTokenBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.out_point.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ChannelToken::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct ParentsVec(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ParentsVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for ParentsVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for ParentsVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for ParentsVec { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ParentsVec::new_unchecked(v) + } +} +impl ParentsVec { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ParentData { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + ParentData::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + ParentData::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> ParentsVecReader<'r> { + ParentsVecReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for ParentsVec { + type Builder = ParentsVecBuilder; + const NAME: &'static str = "ParentsVec"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ParentsVec(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ParentsVecReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ParentsVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct ParentsVecReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ParentsVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for ParentsVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for ParentsVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> ParentsVecReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> ParentDataReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + ParentDataReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + ParentDataReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for ParentsVecReader<'r> { + type Entity = ParentsVec; + const NAME: &'static str = "ParentsVecReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + ParentsVecReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!( + Self, + TotalSizeNotMatch, + molecule::NUMBER_SIZE * 2, + slice_len + ); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + ParentDataReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct ParentsVecBuilder(pub(crate) Vec); +impl ParentsVecBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: ParentData) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: ParentData) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for ParentsVecBuilder { + type Entity = ParentsVec; + const NAME: &'static str = "ParentsVecBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + + self + .0 + .iter() + .map(|inner| inner.as_slice().len()) + .sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number( + molecule::NUMBER_SIZE as molecule::Number, + ))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + ( + molecule::NUMBER_SIZE * (item_count + 1), + Vec::with_capacity(item_count), + ), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + ParentsVec::new_unchecked(inner.into()) + } +} +pub struct ParentsVecIterator(ParentsVec, usize, usize); +impl ::core::iter::Iterator for ParentsVecIterator { + type Item = ParentData; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for ParentsVecIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for ParentsVec { + type Item = ParentData; + type IntoIter = ParentsVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + ParentsVecIterator(self, 0, len) + } +} +impl<'r> ParentsVecReader<'r> { + pub fn iter<'t>(&'t self) -> ParentsVecReaderIterator<'t, 'r> { + ParentsVecReaderIterator(&self, 0, self.len()) + } +} +pub struct ParentsVecReaderIterator<'t, 'r>(&'t ParentsVecReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for ParentsVecReaderIterator<'t, 'r> { + type Item = ParentDataReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for ParentsVecReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::FromIterator for ParentsVec { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} +#[derive(Clone)] +pub struct IndexMap(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for IndexMap { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for IndexMap { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for IndexMap { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) + } +} +impl ::core::default::Default for IndexMap { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + IndexMap::new_unchecked(v) } - pub fn version(&self) -> Uint64 { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Uint64::new_unchecked(self.0.slice(start..end)) +} +impl IndexMap { + const DEFAULT_VALUE: [u8; 2] = [0, 0]; + pub const TOTAL_SIZE: usize = 2; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> Byte { + Byte::new_unchecked(self.0.slice(0..1)) } - pub fn is_final(&self) -> Bool { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - Bool::new_unchecked(self.0.slice(start..end)) - } else { - Bool::new_unchecked(self.0.slice(start..)) - } + pub fn nth1(&self) -> Byte { + Byte::new_unchecked(self.0.slice(1..2)) } - pub fn as_reader<'r>(&'r self) -> ChannelStateReader<'r> { - ChannelStateReader::new_unchecked(self.as_slice()) + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> IndexMapReader<'r> { + IndexMapReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ChannelState { - type Builder = ChannelStateBuilder; - const NAME: &'static str = "ChannelState"; +impl molecule::prelude::Entity for IndexMap { + type Builder = IndexMapBuilder; + const NAME: &'static str = "IndexMap"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelState(data) + IndexMap(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -5903,25 +9039,21 @@ impl molecule::prelude::Entity for ChannelState { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelStateReader::from_slice(slice).map(|reader| reader.to_entity()) + IndexMapReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelStateReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + IndexMapReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder() - .channel_id(self.channel_id()) - .balances(self.balances()) - .version(self.version()) - .is_final(self.is_final()) + Self::new_builder().set([self.nth0(), self.nth1()]) } } #[derive(Clone, Copy)] -pub struct ChannelStateReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelStateReader<'r> { +pub struct IndexMapReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for IndexMapReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -5930,195 +9062,151 @@ impl<'r> ::core::fmt::LowerHex for ChannelStateReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelStateReader<'r> { +impl<'r> ::core::fmt::Debug for IndexMapReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelStateReader<'r> { +impl<'r> ::core::fmt::Display for IndexMapReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "channel_id", self.channel_id())?; - write!(f, ", {}: {}", "balances", self.balances())?; - write!(f, ", {}: {}", "version", self.version())?; - write!(f, ", {}: {}", "is_final", self.is_final())?; - let extra_count = self.count_extra_fields(); - if extra_count != 0 { - write!(f, ", .. ({} fields)", extra_count)?; - } - write!(f, " }}") + use molecule::hex_string; + let raw_data = hex_string(&self.raw_data()); + write!(f, "{}(0x{})", Self::NAME, raw_data) } } -impl<'r> ChannelStateReader<'r> { - pub const FIELD_COUNT: usize = 4; - pub fn total_size(&self) -> usize { - molecule::unpack_number(self.as_slice()) as usize - } - pub fn field_count(&self) -> usize { - if self.total_size() == molecule::NUMBER_SIZE { - 0 - } else { - (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 - } - } - pub fn count_extra_fields(&self) -> usize { - self.field_count() - Self::FIELD_COUNT - } - pub fn has_extra_fields(&self) -> bool { - Self::FIELD_COUNT != self.field_count() - } - pub fn channel_id(&self) -> Byte32Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[4..]) as usize; - let end = molecule::unpack_number(&slice[8..]) as usize; - Byte32Reader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn balances(&self) -> BalancesReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - BalancesReader::new_unchecked(&self.as_slice()[start..end]) +impl<'r> IndexMapReader<'r> { + pub const TOTAL_SIZE: usize = 2; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[0..1]) } - pub fn version(&self) -> Uint64Reader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; - let end = molecule::unpack_number(&slice[16..]) as usize; - Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + pub fn nth1(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[1..2]) } - pub fn is_final(&self) -> BoolReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[16..]) as usize; - if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[20..]) as usize; - BoolReader::new_unchecked(&self.as_slice()[start..end]) - } else { - BoolReader::new_unchecked(&self.as_slice()[start..]) - } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() } } -impl<'r> molecule::prelude::Reader<'r> for ChannelStateReader<'r> { - type Entity = ChannelState; - const NAME: &'static str = "ChannelStateReader"; +impl<'r> molecule::prelude::Reader<'r> for IndexMapReader<'r> { + type Entity = IndexMap; + const NAME: &'static str = "IndexMapReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelStateReader(slice) + IndexMapReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len < molecule::NUMBER_SIZE { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); - } - let total_size = molecule::unpack_number(slice) as usize; - if slice_len != total_size { - return ve!(Self, TotalSizeNotMatch, total_size, slice_len); - } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } - if slice_len < molecule::NUMBER_SIZE * 2 { - return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); - } - let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; - if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { - return ve!(Self, OffsetsNotMatch); - } - if slice_len < offset_first { - return ve!(Self, HeaderIsBroken, offset_first, slice_len); - } - let field_count = offset_first / molecule::NUMBER_SIZE - 1; - if field_count < Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - } else if !compatible && field_count > Self::FIELD_COUNT { - return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); - }; - let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] - .chunks_exact(molecule::NUMBER_SIZE) - .map(|x| molecule::unpack_number(x) as usize) - .collect(); - offsets.push(total_size); - if offsets.windows(2).any(|i| i[0] > i[1]) { - return ve!(Self, OffsetsNotMatch); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - BalancesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - Uint64Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; - BoolReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ChannelStateBuilder { - pub(crate) channel_id: Byte32, - pub(crate) balances: Balances, - pub(crate) version: Uint64, - pub(crate) is_final: Bool, +#[derive(Clone)] +pub struct IndexMapBuilder(pub(crate) [Byte; 2]); +impl ::core::fmt::Debug for IndexMapBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } } -impl ChannelStateBuilder { - pub const FIELD_COUNT: usize = 4; - pub fn channel_id(mut self, v: Byte32) -> Self { - self.channel_id = v; - self +impl ::core::default::Default for IndexMapBuilder { + fn default() -> Self { + IndexMapBuilder([Byte::default(), Byte::default()]) } - pub fn balances(mut self, v: Balances) -> Self { - self.balances = v; +} +impl IndexMapBuilder { + pub const TOTAL_SIZE: usize = 2; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 2; + pub fn set(mut self, v: [Byte; 2]) -> Self { + self.0 = v; self } - pub fn version(mut self, v: Uint64) -> Self { - self.version = v; + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; self } - pub fn is_final(mut self, v: Bool) -> Self { - self.is_final = v; + pub fn nth1(mut self, v: Byte) -> Self { + self.0[1] = v; self } } -impl molecule::prelude::Builder for ChannelStateBuilder { - type Entity = ChannelState; - const NAME: &'static str = "ChannelStateBuilder"; +impl molecule::prelude::Builder for IndexMapBuilder { + type Entity = IndexMap; + const NAME: &'static str = "IndexMapBuilder"; fn expected_length(&self) -> usize { - molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.channel_id.as_slice().len() - + self.balances.as_slice().len() - + self.version.as_slice().len() - + self.is_final.as_slice().len() + Self::TOTAL_SIZE } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); - let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); - offsets.push(total_size); - total_size += self.channel_id.as_slice().len(); - offsets.push(total_size); - total_size += self.balances.as_slice().len(); - offsets.push(total_size); - total_size += self.version.as_slice().len(); - offsets.push(total_size); - total_size += self.is_final.as_slice().len(); - writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; - for offset in offsets.into_iter() { - writer.write_all(&molecule::pack_number(offset as molecule::Number))?; - } - writer.write_all(self.channel_id.as_slice())?; - writer.write_all(self.balances.as_slice())?; - writer.write_all(self.version.as_slice())?; - writer.write_all(self.is_final.as_slice())?; + writer.write_all(self.0[0].as_slice())?; + writer.write_all(self.0[1].as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelState::new_unchecked(inner.into()) + IndexMap::new_unchecked(inner.into()) + } +} +impl From<[Byte; 2usize]> for IndexMap { + fn from(value: [Byte; 2usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for IndexMap { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 2usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 2usize] { + #[track_caller] + fn from(value: IndexMap) -> Self { + [value.nth0(), value.nth1()] + } +} +impl From<[u8; 2usize]> for IndexMap { + fn from(value: [u8; 2usize]) -> Self { + IndexMapReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for IndexMap { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 2usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 2usize] { + #[track_caller] + fn from(value: IndexMap) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 2usize] { + #[track_caller] + fn from(value: IndexMapReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a IndexMapReader<'a>> for &'a [u8; 2usize] { + #[track_caller] + fn from(value: &'a IndexMapReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() } } #[derive(Clone)] -pub struct ChannelStatus(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelStatus { +pub struct ParentData(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for ParentData { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -6127,17 +9215,16 @@ impl ::core::fmt::LowerHex for ChannelStatus { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ChannelStatus { +impl ::core::fmt::Debug for ParentData { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ChannelStatus { +impl ::core::fmt::Display for ParentData { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "state", self.state())?; - write!(f, ", {}: {}", "funded", self.funded())?; - write!(f, ", {}: {}", "disputed", self.disputed())?; + write!(f, "{}: {}", "pcts_hash", self.pcts_hash())?; + write!(f, ", {}: {}", "idx_map", self.idx_map())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -6145,20 +9232,18 @@ impl ::core::fmt::Display for ChannelStatus { write!(f, " }}") } } -impl ::core::default::Default for ChannelStatus { +impl ::core::default::Default for ParentData { fn default() -> Self { - let v: Vec = vec![ - 123, 0, 0, 0, 16, 0, 0, 0, 113, 0, 0, 0, 118, 0, 0, 0, 97, 0, 0, 0, 20, 0, 0, 0, 52, 0, - 0, 0, 84, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 28, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - ChannelStatus::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + ParentData::new_unchecked(v) } } -impl ChannelStatus { - pub const FIELD_COUNT: usize = 3; +impl ParentData { + const DEFAULT_VALUE: [u8; 46] = [ + 46, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -6175,37 +9260,31 @@ impl ChannelStatus { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn state(&self) -> ChannelState { + pub fn pcts_hash(&self) -> Byte32 { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelState::new_unchecked(self.0.slice(start..end)) + Byte32::new_unchecked(self.0.slice(start..end)) } - pub fn funded(&self) -> Bool { + pub fn idx_map(&self) -> IndexMap { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - Bool::new_unchecked(self.0.slice(start..end)) - } - pub fn disputed(&self) -> Bool { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - Bool::new_unchecked(self.0.slice(start..end)) + let end = molecule::unpack_number(&slice[12..]) as usize; + IndexMap::new_unchecked(self.0.slice(start..end)) } else { - Bool::new_unchecked(self.0.slice(start..)) + IndexMap::new_unchecked(self.0.slice(start..)) } } - pub fn as_reader<'r>(&'r self) -> ChannelStatusReader<'r> { - ChannelStatusReader::new_unchecked(self.as_slice()) + pub fn as_reader<'r>(&'r self) -> ParentDataReader<'r> { + ParentDataReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ChannelStatus { - type Builder = ChannelStatusBuilder; - const NAME: &'static str = "ChannelStatus"; +impl molecule::prelude::Entity for ParentData { + type Builder = ParentDataBuilder; + const NAME: &'static str = "ParentData"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelStatus(data) + ParentData(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -6214,24 +9293,23 @@ impl molecule::prelude::Entity for ChannelStatus { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelStatusReader::from_slice(slice).map(|reader| reader.to_entity()) + ParentDataReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelStatusReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + ParentDataReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { Self::new_builder() - .state(self.state()) - .funded(self.funded()) - .disputed(self.disputed()) + .pcts_hash(self.pcts_hash()) + .idx_map(self.idx_map()) } } #[derive(Clone, Copy)] -pub struct ChannelStatusReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelStatusReader<'r> { +pub struct ParentDataReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for ParentDataReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -6240,17 +9318,16 @@ impl<'r> ::core::fmt::LowerHex for ChannelStatusReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelStatusReader<'r> { +impl<'r> ::core::fmt::Debug for ParentDataReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelStatusReader<'r> { +impl<'r> ::core::fmt::Display for ParentDataReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "state", self.state())?; - write!(f, ", {}: {}", "funded", self.funded())?; - write!(f, ", {}: {}", "disputed", self.disputed())?; + write!(f, "{}: {}", "pcts_hash", self.pcts_hash())?; + write!(f, ", {}: {}", "idx_map", self.idx_map())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -6258,8 +9335,8 @@ impl<'r> ::core::fmt::Display for ChannelStatusReader<'r> { write!(f, " }}") } } -impl<'r> ChannelStatusReader<'r> { - pub const FIELD_COUNT: usize = 3; +impl<'r> ParentDataReader<'r> { + pub const FIELD_COUNT: usize = 2; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -6276,37 +9353,31 @@ impl<'r> ChannelStatusReader<'r> { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn state(&self) -> ChannelStateReader<'r> { + pub fn pcts_hash(&self) -> Byte32Reader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[4..]) as usize; let end = molecule::unpack_number(&slice[8..]) as usize; - ChannelStateReader::new_unchecked(&self.as_slice()[start..end]) + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) } - pub fn funded(&self) -> BoolReader<'r> { + pub fn idx_map(&self) -> IndexMapReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[8..]) as usize; - let end = molecule::unpack_number(&slice[12..]) as usize; - BoolReader::new_unchecked(&self.as_slice()[start..end]) - } - pub fn disputed(&self) -> BoolReader<'r> { - let slice = self.as_slice(); - let start = molecule::unpack_number(&slice[12..]) as usize; if self.has_extra_fields() { - let end = molecule::unpack_number(&slice[16..]) as usize; - BoolReader::new_unchecked(&self.as_slice()[start..end]) + let end = molecule::unpack_number(&slice[12..]) as usize; + IndexMapReader::new_unchecked(&self.as_slice()[start..end]) } else { - BoolReader::new_unchecked(&self.as_slice()[start..]) + IndexMapReader::new_unchecked(&self.as_slice()[start..]) } } } -impl<'r> molecule::prelude::Reader<'r> for ChannelStatusReader<'r> { - type Entity = ChannelStatus; - const NAME: &'static str = "ChannelStatusReader"; +impl<'r> molecule::prelude::Reader<'r> for ParentDataReader<'r> { + type Entity = ParentData; + const NAME: &'static str = "ParentDataReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelStatusReader(slice) + ParentDataReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 @@ -6321,9 +9392,6 @@ impl<'r> molecule::prelude::Reader<'r> for ChannelStatusReader<'r> { if slice_len != total_size { return ve!(Self, TotalSizeNotMatch, total_size, slice_len); } - if slice_len == molecule::NUMBER_SIZE && Self::FIELD_COUNT == 0 { - return Ok(()); - } if slice_len < molecule::NUMBER_SIZE * 2 { return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); } @@ -6348,70 +9416,60 @@ impl<'r> molecule::prelude::Reader<'r> for ChannelStatusReader<'r> { if offsets.windows(2).any(|i| i[0] > i[1]) { return ve!(Self, OffsetsNotMatch); } - ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; - BoolReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; - BoolReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + IndexMapReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ChannelStatusBuilder { - pub(crate) state: ChannelState, - pub(crate) funded: Bool, - pub(crate) disputed: Bool, +#[derive(Clone, Debug, Default)] +pub struct ParentDataBuilder { + pub(crate) pcts_hash: Byte32, + pub(crate) idx_map: IndexMap, } -impl ChannelStatusBuilder { - pub const FIELD_COUNT: usize = 3; - pub fn state(mut self, v: ChannelState) -> Self { - self.state = v; - self - } - pub fn funded(mut self, v: Bool) -> Self { - self.funded = v; +impl ParentDataBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn pcts_hash(mut self, v: Byte32) -> Self { + self.pcts_hash = v; self } - pub fn disputed(mut self, v: Bool) -> Self { - self.disputed = v; + pub fn idx_map(mut self, v: IndexMap) -> Self { + self.idx_map = v; self } } -impl molecule::prelude::Builder for ChannelStatusBuilder { - type Entity = ChannelStatus; - const NAME: &'static str = "ChannelStatusBuilder"; +impl molecule::prelude::Builder for ParentDataBuilder { + type Entity = ParentData; + const NAME: &'static str = "ParentDataBuilder"; fn expected_length(&self) -> usize { molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) - + self.state.as_slice().len() - + self.funded.as_slice().len() - + self.disputed.as_slice().len() + + self.pcts_hash.as_slice().len() + + self.idx_map.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); offsets.push(total_size); - total_size += self.state.as_slice().len(); - offsets.push(total_size); - total_size += self.funded.as_slice().len(); + total_size += self.pcts_hash.as_slice().len(); offsets.push(total_size); - total_size += self.disputed.as_slice().len(); + total_size += self.idx_map.as_slice().len(); writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; for offset in offsets.into_iter() { writer.write_all(&molecule::pack_number(offset as molecule::Number))?; } - writer.write_all(self.state.as_slice())?; - writer.write_all(self.funded.as_slice())?; - writer.write_all(self.disputed.as_slice())?; + writer.write_all(self.pcts_hash.as_slice())?; + writer.write_all(self.idx_map.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelStatus::new_unchecked(inner.into()) + ParentData::new_unchecked(inner.into()) } } #[derive(Clone)] -pub struct ChannelToken(molecule::bytes::Bytes); -impl ::core::fmt::LowerHex for ChannelToken { +pub struct VirtualChannelStatus(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for VirtualChannelStatus { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -6420,43 +9478,97 @@ impl ::core::fmt::LowerHex for ChannelToken { write!(f, "{}", hex_string(self.as_slice())) } } -impl ::core::fmt::Debug for ChannelToken { +impl ::core::fmt::Debug for VirtualChannelStatus { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl ::core::fmt::Display for ChannelToken { +impl ::core::fmt::Display for VirtualChannelStatus { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "out_point", self.out_point())?; + write!(f, "{}: {}", "vcstate", self.vcstate())?; + write!(f, ", {}: {}", "parents", self.parents())?; + write!(f, ", {}: {}", "first_force_close", self.first_force_close())?; + write!(f, ", {}: {}", "owner", self.owner())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } write!(f, " }}") } } -impl ::core::default::Default for ChannelToken { +impl ::core::default::Default for VirtualChannelStatus { fn default() -> Self { - let v: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, - ]; - ChannelToken::new_unchecked(v.into()) + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + VirtualChannelStatus::new_unchecked(v) + } +} +impl VirtualChannelStatus { + const DEFAULT_VALUE: [u8; 259] = [ + 3, 1, 0, 0, 20, 0, 0, 0, 125, 0, 0, 0, 129, 0, 0, 0, 134, 0, 0, 0, 105, 0, 0, 0, 20, 0, 0, + 0, 52, 0, 0, 0, 92, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 36, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 20, 0, 0, 0, 52, 0, + 0, 0, 60, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize } -} -impl ChannelToken { - pub const TOTAL_SIZE: usize = 36; - pub const FIELD_SIZES: [usize; 1] = [36]; - pub const FIELD_COUNT: usize = 1; - pub fn out_point(&self) -> OutPoint { - OutPoint::new_unchecked(self.0.slice(0..36)) + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } } - pub fn as_reader<'r>(&'r self) -> ChannelTokenReader<'r> { - ChannelTokenReader::new_unchecked(self.as_slice()) + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn vcstate(&self) -> ChannelState { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelState::new_unchecked(self.0.slice(start..end)) + } + pub fn parents(&self) -> ParentsVec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + ParentsVec::new_unchecked(self.0.slice(start..end)) + } + pub fn first_force_close(&self) -> Bool { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Bool::new_unchecked(self.0.slice(start..end)) + } + pub fn owner(&self) -> Participant { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + Participant::new_unchecked(self.0.slice(start..end)) + } else { + Participant::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> VirtualChannelStatusReader<'r> { + VirtualChannelStatusReader::new_unchecked(self.as_slice()) } } -impl molecule::prelude::Entity for ChannelToken { - type Builder = ChannelTokenBuilder; - const NAME: &'static str = "ChannelToken"; +impl molecule::prelude::Entity for VirtualChannelStatus { + type Builder = VirtualChannelStatusBuilder; + const NAME: &'static str = "VirtualChannelStatus"; fn new_unchecked(data: molecule::bytes::Bytes) -> Self { - ChannelToken(data) + VirtualChannelStatus(data) } fn as_bytes(&self) -> molecule::bytes::Bytes { self.0.clone() @@ -6465,21 +9577,25 @@ impl molecule::prelude::Entity for ChannelToken { &self.0[..] } fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelTokenReader::from_slice(slice).map(|reader| reader.to_entity()) + VirtualChannelStatusReader::from_slice(slice).map(|reader| reader.to_entity()) } fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { - ChannelTokenReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + VirtualChannelStatusReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) } fn new_builder() -> Self::Builder { ::core::default::Default::default() } fn as_builder(self) -> Self::Builder { - Self::new_builder().out_point(self.out_point()) + Self::new_builder() + .vcstate(self.vcstate()) + .parents(self.parents()) + .first_force_close(self.first_force_close()) + .owner(self.owner()) } } #[derive(Clone, Copy)] -pub struct ChannelTokenReader<'r>(&'r [u8]); -impl<'r> ::core::fmt::LowerHex for ChannelTokenReader<'r> { +pub struct VirtualChannelStatusReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for VirtualChannelStatusReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { use molecule::hex_string; if f.alternate() { @@ -6488,74 +9604,186 @@ impl<'r> ::core::fmt::LowerHex for ChannelTokenReader<'r> { write!(f, "{}", hex_string(self.as_slice())) } } -impl<'r> ::core::fmt::Debug for ChannelTokenReader<'r> { +impl<'r> ::core::fmt::Debug for VirtualChannelStatusReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}({:#x})", Self::NAME, self) } } -impl<'r> ::core::fmt::Display for ChannelTokenReader<'r> { +impl<'r> ::core::fmt::Display for VirtualChannelStatusReader<'r> { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{} {{ ", Self::NAME)?; - write!(f, "{}: {}", "out_point", self.out_point())?; + write!(f, "{}: {}", "vcstate", self.vcstate())?; + write!(f, ", {}: {}", "parents", self.parents())?; + write!(f, ", {}: {}", "first_force_close", self.first_force_close())?; + write!(f, ", {}: {}", "owner", self.owner())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } write!(f, " }}") } } -impl<'r> ChannelTokenReader<'r> { - pub const TOTAL_SIZE: usize = 36; - pub const FIELD_SIZES: [usize; 1] = [36]; - pub const FIELD_COUNT: usize = 1; - pub fn out_point(&self) -> OutPointReader<'r> { - OutPointReader::new_unchecked(&self.as_slice()[0..36]) +impl<'r> VirtualChannelStatusReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn vcstate(&self) -> ChannelStateReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ChannelStateReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn parents(&self) -> ParentsVecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + ParentsVecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn first_force_close(&self) -> BoolReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + BoolReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn owner(&self) -> ParticipantReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + ParticipantReader::new_unchecked(&self.as_slice()[start..end]) + } else { + ParticipantReader::new_unchecked(&self.as_slice()[start..]) + } } } -impl<'r> molecule::prelude::Reader<'r> for ChannelTokenReader<'r> { - type Entity = ChannelToken; - const NAME: &'static str = "ChannelTokenReader"; +impl<'r> molecule::prelude::Reader<'r> for VirtualChannelStatusReader<'r> { + type Entity = VirtualChannelStatus; + const NAME: &'static str = "VirtualChannelStatusReader"; fn to_entity(&self) -> Self::Entity { Self::Entity::new_unchecked(self.as_slice().to_owned().into()) } fn new_unchecked(slice: &'r [u8]) -> Self { - ChannelTokenReader(slice) + VirtualChannelStatusReader(slice) } fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::verification_error as ve; let slice_len = slice.len(); - if slice_len != Self::TOTAL_SIZE { - return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + ParentsVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BoolReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + ParticipantReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; Ok(()) } } -#[derive(Debug, Default)] -pub struct ChannelTokenBuilder { - pub(crate) out_point: OutPoint, +#[derive(Clone, Debug, Default)] +pub struct VirtualChannelStatusBuilder { + pub(crate) vcstate: ChannelState, + pub(crate) parents: ParentsVec, + pub(crate) first_force_close: Bool, + pub(crate) owner: Participant, } -impl ChannelTokenBuilder { - pub const TOTAL_SIZE: usize = 36; - pub const FIELD_SIZES: [usize; 1] = [36]; - pub const FIELD_COUNT: usize = 1; - pub fn out_point(mut self, v: OutPoint) -> Self { - self.out_point = v; +impl VirtualChannelStatusBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn vcstate(mut self, v: ChannelState) -> Self { + self.vcstate = v; + self + } + pub fn parents(mut self, v: ParentsVec) -> Self { + self.parents = v; + self + } + pub fn first_force_close(mut self, v: Bool) -> Self { + self.first_force_close = v; + self + } + pub fn owner(mut self, v: Participant) -> Self { + self.owner = v; self } } -impl molecule::prelude::Builder for ChannelTokenBuilder { - type Entity = ChannelToken; - const NAME: &'static str = "ChannelTokenBuilder"; +impl molecule::prelude::Builder for VirtualChannelStatusBuilder { + type Entity = VirtualChannelStatus; + const NAME: &'static str = "VirtualChannelStatusBuilder"; fn expected_length(&self) -> usize { - Self::TOTAL_SIZE + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.vcstate.as_slice().len() + + self.parents.as_slice().len() + + self.first_force_close.as_slice().len() + + self.owner.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { - writer.write_all(self.out_point.as_slice())?; + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.vcstate.as_slice().len(); + offsets.push(total_size); + total_size += self.parents.as_slice().len(); + offsets.push(total_size); + total_size += self.first_force_close.as_slice().len(); + offsets.push(total_size); + total_size += self.owner.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.vcstate.as_slice())?; + writer.write_all(self.parents.as_slice())?; + writer.write_all(self.first_force_close.as_slice())?; + writer.write_all(self.owner.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { let mut inner = Vec::with_capacity(self.expected_length()); self.write(&mut inner) .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); - ChannelToken::new_unchecked(inner.into()) + VirtualChannelStatus::new_unchecked(inner.into()) } } diff --git a/payment-channel-ckb/devnet/contracts/crates/perun-common/src/sig.rs b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/sig.rs new file mode 100644 index 0000000..6c8ae1b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/src/sig.rs @@ -0,0 +1,34 @@ +use k256::{ + ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}, + elliptic_curve::sec1::EncodedPoint, + Secp256k1, +}; +use sha3::{Digest, Keccak256}; + +use crate::error::Error; + +pub fn verify_signature(msg_hash: &[u8; 32], sig: &[u8], key: &[u8]) -> Result<(), Error> { + let signature = Signature::from_der(sig)?; + let e = EncodedPoint::::from_bytes(key).expect("unable to decode public key"); + let verifying_key = VerifyingKey::from_encoded_point(&e)?; + verifying_key.verify_prehash(msg_hash, &signature)?; + Ok(()) +} + +/// Replaces `blake2b256(data)` — hashes with Ethereum message prefix +pub fn ethereum_message_hash(data: &[u8]) -> [u8; 32] { + // First keccak256 hash of the message + let msg_hash = Keccak256::digest(data); + + // Ethereum message prefix: "\x19Ethereum Signed Message:\n32" + let mut prefix = b"\x19Ethereum Signed Message:\n32".to_vec(); + prefix.extend_from_slice(&msg_hash); + + // Second keccak256 hash of the prefixed data + let final_hash = Keccak256::digest(&prefix); + + final_hash + .as_slice() + .try_into() + .expect("Ethereum message hash must be 32 bytes") +} \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/types.mol b/payment-channel-ckb/devnet/contracts/crates/perun-common/types.mol similarity index 83% rename from payment-channel-ckb/devnet/contracts/contracts/perun-common/types.mol rename to payment-channel-ckb/devnet/contracts/crates/perun-common/types.mol index 5fa3a5f..04d1012 100644 --- a/payment-channel-ckb/devnet/contracts/contracts/perun-common/types.mol +++ b/payment-channel-ckb/devnet/contracts/crates/perun-common/types.mol @@ -9,6 +9,18 @@ array SUDTDistribution [Uint128; 2]; vector SUDTAllocation ; +vector Locked_balances ; + +table SubAlloc{ + id: Byte32, //subchannel/virtual channel id + balances: SubBalances, +} + +table SubBalances{ + ckbytes: CKByteDistribution, + sudts: SUDTAllocation, +} + table SUDTAsset { type_script: Script, // The max_capacity of an SUDTAsset should always be at least the capacity needed for the SUDT type script + outputs_data @@ -25,6 +37,7 @@ table SUDTBalances { table Balances { ckbytes: CKByteDistribution, sudts: SUDTAllocation, + locked: Locked_balances, } array True [byte; 1]; @@ -70,9 +83,7 @@ table ChannelParameters { challenge_duration: Uint64, // The default should be NoApp! app: App, - // This should always be set to true for, as we currently only support ledger channels. is_ledger_channel: Bool, - // This should always be set to false for, as we currently do not support virtual channels. is_virtual_channel: Bool, } @@ -97,10 +108,21 @@ table ChannelConstants { thread_token: ChannelToken, } +table VCChannelConstants{ + params: ChannelParameters, + vcls_code_hash: Byte32, + vcls_hash_type: byte, +} array Fund [byte; 1]; array Abort [byte; 1]; +table VCDispute { + sig_a: Bytes, + sig_b: Bytes, + parent_state_sigs: Dispute, +} + table Dispute { sig_a: Bytes, sig_b: Bytes, @@ -112,17 +134,16 @@ table Close { } array ForceClose [byte; 1]; - union ChannelWitness { Fund, Abort, Dispute, + VCDispute, Close, ForceClose, } table ChannelState { - // channel_id: Byte32, balances: Balances, version: Uint64, @@ -133,8 +154,27 @@ table ChannelStatus { state: ChannelState, funded: Bool, disputed: Bool, + vc_disputed: Bool, + vcts_hash: Byte32, } struct ChannelToken { out_point: OutPoint, -} \ No newline at end of file +} + +vector ParentsVec; + +array index_map[byte;2]; + +table ParentData { + pcts_hash: Byte32, + idx_map: index_map, +} + + +table VirtualChannelStatus { + vcstate: ChannelState, + parents: ParentsVec, + first_force_close: Bool, + owner: Participant, +} diff --git a/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml index 68c528d..0595e8c 100644 --- a/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml +++ b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml @@ -1,3 +1,8 @@ +[[cells]] +name = "sudt" +enable_type_id = false +location = { file = "build/release/sample-udt" } + [[cells]] name = "pcts" enable_type_id = false @@ -13,11 +18,6 @@ name = "pfls" enable_type_id = false location = { file = "build/release/perun-funds-lockscript" } -[[cells]] -name = "sudt" -enable_type_id = false -location = { file = "build/release/sample-udt" } - # # # reference to on-chain cells # [[cells]] @@ -37,5 +37,5 @@ location = { file = "build/release/sample-udt" } # # For example the secp256k1 lock [lock] code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" -args = "0xce66f2898d070aea2bb0edf2823e27338f467dad" +args = "0x2094d311d690999f7c59f3f45b060cd2bb19b394" hash_type = "type" diff --git a/payment-channel-ckb/devnet/contracts/deployment/dev/deployment_vc.toml b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment_vc.toml new file mode 100644 index 0000000..296d33c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment_vc.toml @@ -0,0 +1,31 @@ +[[cells]] +name = "vcts" +enable_type_id = false +location = { file = "build/release/perun-vchannel-typescript" } + +[[cells]] +name = "vcls" +enable_type_id = false +location = { file = "build/release/perun-vchannel-lockscript" } + +# +# # reference to on-chain cells +# [[cells]] +# name = "genesis_cell" +# enable_type_id = false +# location = { tx_hash = "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c", index = 0 } + +# # Dep group cells +# [[dep_groups]] +# name = "my_dep_group" +# cells = [ +# "my_cell", +# "genesis_cell" +# ] + +# # Replace with your own lock if you want to unlock deployed cells. +# # For example the secp256k1 lock +[lock] +code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +args = "0x2094d311d690999f7c59f3f45b060cd2bb19b394" +hash_type = "type" diff --git a/payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml b/payment-channel-ckb/devnet/contracts/deployment/release/deployment_vc.toml similarity index 71% rename from payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml rename to payment-channel-ckb/devnet/contracts/deployment/release/deployment_vc.toml index 65968f5..0152b9a 100644 --- a/payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml +++ b/payment-channel-ckb/devnet/contracts/deployment/release/deployment_vc.toml @@ -1,17 +1,12 @@ [[cells]] -name = "pcts" +name = "vcts" enable_type_id = false -location = { file = "build/release/perun-channel-typescript" } +location = { file = "build/release/perun-vchannel-typescript" } [[cells]] -name = "pcls" +name = "vcls" enable_type_id = false -location = { file = "build/release/perun-channel-lockscript" } - -[[cells]] -name = "pfls" -enable_type_id = false -location = { file = "build/release/perun-funds-lockscript" } +location = { file = "build/release/perun-vchannel-lockscript" } # # # reference to on-chain cells @@ -34,4 +29,3 @@ location = { file = "build/release/perun-funds-lockscript" } # code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" # args = "0x1edcdab5ec7e0f748c60815fce513ee1fe4d63ee" # hash_type = "type" - diff --git a/payment-channel-ckb/devnet/contracts/migrations_vc/.gitkeep b/payment-channel-ckb/devnet/contracts/migrations_vc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/payment-channel-ckb/devnet/contracts/scripts/find_clang b/payment-channel-ckb/devnet/contracts/scripts/find_clang new file mode 100755 index 0000000..e62a84e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/scripts/find_clang @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# +# An utility script used to find a binary of clang 16+ + +if [[ -n "${CLANG}" ]]; then + echo "${CLANG}" + exit 0 +fi + +# To cope with packaging messes from different distros, we would search +# for a different binary other than clang, then convert it back to clang +# at the end. +SEARCH_TARGET="${SEARCH_TARGET:-llvm-strip}" + +CANDIDATES=("${SEARCH_TARGET}" "${SEARCH_TARGET}-19" "${SEARCH_TARGET}-18" "${SEARCH_TARGET}-17" "${SEARCH_TARGET}-16") + +BREW_PREFIX=$(brew --prefix 2> /dev/null) +if [[ -n "${BREW_PREFIX}" ]]; then + CANDIDATES+=( + "${BREW_PREFIX}/opt/llvm/bin/${SEARCH_TARGET}" + "${BREW_PREFIX}/opt/llvm@19/bin/${SEARCH_TARGET}" + "${BREW_PREFIX}/opt/llvm@18/bin/${SEARCH_TARGET}" + "${BREW_PREFIX}/opt/llvm@17/bin/${SEARCH_TARGET}" + "${BREW_PREFIX}/opt/llvm@16/bin/${SEARCH_TARGET}" + ) +fi + +for candidate in ${CANDIDATES[@]}; do + OUTPUT=$($candidate --version 2> /dev/null | grep 'version [0-9]' | head -n 1 | cut -d'.' -f 1 | grep -o '[0-9][0-9]*') + + if [[ $((OUTPUT)) -ge 16 ]]; then + echo "${candidate/${SEARCH_TARGET}/clang}" + exit 0 + fi +done + +>&2 echo "Cannot find clang of version 16+!" +exit 1 diff --git a/payment-channel-ckb/devnet/contracts/scripts/reproducible_build_docker b/payment-channel-ckb/devnet/contracts/scripts/reproducible_build_docker new file mode 100755 index 0000000..55bba0d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/scripts/reproducible_build_docker @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# An utility script helping with reproducible script builds via docker. +# Note that this utility serves only as one example, docker is not +# necessarily THE way to do reproducible build, nor is it the best way +# to do reproducible build. +set -ex + +DOCKER="${DOCKER:-docker}" +# docker pull docker.io/cryptape/llvm-n-rust:20250117 +DOCKER_IMAGE="${DOCKER_IMAGE:-docker.io/cryptape/llvm-n-rust@sha256:12e7821cb9c7cbc8988d5b1d60bcc87da4cedcf3eea32df1d8833328c5a69f88}" +CHECKSUM_FILE_PATH="${CHECKSUM_FILE_PATH:-checksums.txt}" + +# We are parsing command line arguments based on tips from: +# https://stackoverflow.com/a/14203146 + +while [[ $# -gt 0 ]]; do + case $1 in + -p|--proxy) + PROXY="$2" + shift # past argument + shift # past value + ;; + -u|--update) + UPDATE="yes" + shift # past argument + ;; + --no-clean) + NOCLEAN="yes" + shift # past argument + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + echo "Unknown argument $1" + exit 1 + ;; + esac +done + +if [[ -n "${PROXY}" ]]; then + DOCKER_RUN_ARGS="-e ALL_PROXY=${PROXY} -e HTTPS_PROXY=${PROXY} -e HTTP_PROXY=${PROXY} ${DOCKER_RUN_ARGS}" +fi + +TASKS="" +if [[ "${NOCLEAN}" != "yes" ]]; then + TASKS+=" clean " +fi + +if [[ "${UPDATE}" = "yes" ]]; then + TASKS+=" checksum CHECKSUM_FILE=${CHECKSUM_FILE_PATH} " +else + TASKS+=" build " +fi + +$DOCKER run --rm $DOCKER_RUN_ARGS -v `pwd`:/code $DOCKER_IMAGE make $TASKS +# Reset file ownerships for all files docker might touch +$DOCKER run --rm $DOCKER_RUN_ARGS -e UID=`id -u` -e GID=`id -g` -v `pwd`:/code $DOCKER_IMAGE bash -c 'chown -R -f $UID:$GID checksums.txt build target' + +if [[ "${UPDATE}" = "yes" ]]; then + echo "${CHECKSUM_FILE_PATH} file is updated with latest binary hashes!" +else + shasum -a 256 -c ${CHECKSUM_FILE_PATH} +fi diff --git a/payment-channel-ckb/devnet/contracts/setup_env.sh b/payment-channel-ckb/devnet/contracts/setup_env.sh new file mode 100755 index 0000000..f82de5f --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/setup_env.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# Helper script to set the correct environment for build and test + +if [ "$1" = "build" ]; then + echo "🔧 Setting environment for BUILD (RISC-V)..." + export RUSTFLAGS="-C linker=rust-lld" + export CARGO_TARGET_RISCV64IMAC_UNKNOWN_NONE_ELF_LINKER=rust-lld + export TARGET_CC=riscv64-unknown-elf-gcc + export TARGET_AR=riscv64-unknown-elf-ar + export C_INCLUDE_PATH=/usr/riscv64-linux-gnu/include + export CFLAGS="-I/usr/riscv64-linux-gnu/include" + export TARGET_CFLAGS="-I/usr/riscv64-linux-gnu/include" + export CC=clang-18 + +elif [ "$1" = "test" ]; then + echo "🧪 Setting environment for TEST (x86_64)..." + export RUSTFLAGS="" + unset CARGO_TARGET_RISCV64IMAC_UNKNOWN_NONE_ELF_LINKER + unset TARGET_CC + unset TARGET_AR + unset C_INCLUDE_PATH + unset CFLAGS + unset TARGET_CFLAGS + unset CC + export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="gcc" + +fi diff --git a/payment-channel-ckb/devnet/contracts/tests/Cargo.lock b/payment-channel-ckb/devnet/contracts/tests/Cargo.lock deleted file mode 100644 index d7d027c..0000000 --- a/payment-channel-ckb/devnet/contracts/tests/Cargo.lock +++ /dev/null @@ -1,1593 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.9", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2b-ref" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95916998c798756098a4eb1b3f2cd510659705a9817bf203d61abd30fbec3e7b" - -[[package]] -name = "blake2b-rs" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89a8565807f21b913288968e391819e7f9b2f0f46c7b89549c051cccf3a2771" -dependencies = [ - "cc", - "cty", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "buddy-alloc" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "ckb-always-success-script" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3b72a38c9920a29990df12002c4d069a147c8782f0c211f8a01b2df8f42bfd" - -[[package]] -name = "ckb-chain-spec" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78df45446aaa86b06a77b8b145cffa79950e7ede293cebcd114a62e74c29dbf" -dependencies = [ - "ckb-constant", - "ckb-crypto", - "ckb-dao-utils", - "ckb-error", - "ckb-hash", - "ckb-jsonrpc-types", - "ckb-pow", - "ckb-rational", - "ckb-resource", - "ckb-traits", - "ckb-types", - "ckb-util", - "serde", - "toml", -] - -[[package]] -name = "ckb-channel" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920f26cc48cadcaf6f7bcc3960fde9f9f355633b6361da8ef31e1e1c00fc8858" -dependencies = [ - "crossbeam-channel", -] - -[[package]] -name = "ckb-constant" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302566408e5b296663ac5e8245bf71824ca2c7c2ef19a57fcc15939dd66527e9" - -[[package]] -name = "ckb-crypto" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac31177b0a8bf3acd563c042775e40494e437b2bbbae96ac2473eec3a4da95d" -dependencies = [ - "ckb-fixed-hash", - "faster-hex", - "lazy_static", - "rand 0.7.3", - "secp256k1", - "thiserror", -] - -[[package]] -name = "ckb-dao" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b70944b9013ead64287b87ac19608a3ca5ab19a9f29b7a76f637ad7831510e88" -dependencies = [ - "byteorder", - "ckb-chain-spec", - "ckb-dao-utils", - "ckb-traits", - "ckb-types", -] - -[[package]] -name = "ckb-dao-utils" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1929c9627923fe1d22151361d74f5a5aa0dda77016d020307a54486eae11cb3c" -dependencies = [ - "byteorder", - "ckb-error", - "ckb-types", -] - -[[package]] -name = "ckb-error" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446a519d8a847d97f1c8ece739dc1748751a9a2179249c96c45cced0825a7aa5" -dependencies = [ - "anyhow", - "ckb-occupied-capacity", - "derive_more", - "thiserror", -] - -[[package]] -name = "ckb-fixed-hash" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00cbbc455b23748b32e06d16628a03e30d56ffa057f17093fdf5b42d4fb6c879" -dependencies = [ - "ckb-fixed-hash-core", - "ckb-fixed-hash-macros", -] - -[[package]] -name = "ckb-fixed-hash-core" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e644a4e026625b4be5a04cdf6c02043080e79feaf77d9cdbb2f0e6553f751" -dependencies = [ - "faster-hex", - "serde", - "thiserror", -] - -[[package]] -name = "ckb-fixed-hash-macros" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cfc980ef88c217825172eb46df269f47890f5e78a38214416f13b3bd17a4b4" -dependencies = [ - "ckb-fixed-hash-core", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ckb-hash" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d9b683e89ae4ffdd5aaf4172eab00b6bbe7ea24e2abf77d3eb850ba36e8983" -dependencies = [ - "blake2b-ref", - "blake2b-rs", -] - -[[package]] -name = "ckb-jsonrpc-types" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac087657eaf964e729f40b3c929d3dac74a2cd8bb38d5e588756e2495711f810" -dependencies = [ - "ckb-types", - "faster-hex", - "serde", - "serde_json", -] - -[[package]] -name = "ckb-logger" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "911c4695ddf82f78da8f514b359092bbe231f58c2669c93b1cfc9a2030b125bb" -dependencies = [ - "log", -] - -[[package]] -name = "ckb-merkle-mountain-range" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ckb-occupied-capacity" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2a1dd0d4ba5dafba1e30d437c1148b20f42edb76b6794323e05bda626754eb" -dependencies = [ - "ckb-occupied-capacity-core", - "ckb-occupied-capacity-macros", -] - -[[package]] -name = "ckb-occupied-capacity-core" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ebba3d564098a84c83f4740e1dce48a5e2da759becdb47e3c7965f0808e6e92" -dependencies = [ - "serde", -] - -[[package]] -name = "ckb-occupied-capacity-macros" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6321bba85cdf9724029d8c906851dd4a90906869b42f9100b16645a1261d4c" -dependencies = [ - "ckb-occupied-capacity-core", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ckb-pow" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9167b427f42874e68e20e6946d5211709979ff1d86c0061a71c2f6a6aa17659" -dependencies = [ - "byteorder", - "ckb-hash", - "ckb-types", - "eaglesong", - "log", - "serde", -] - -[[package]] -name = "ckb-rational" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2519249f8d47fa758d3fb3cf3049327c69ce0f2acd79d61427482c8661d3dbd" -dependencies = [ - "numext-fixed-uint", - "serde", -] - -[[package]] -name = "ckb-resource" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3abddc968d7f1e70584ab04180c347380a44acbe0b60e26cc96208ec8885279" -dependencies = [ - "ckb-system-scripts", - "ckb-types", - "includedir", - "includedir_codegen", - "phf", - "serde", - "walkdir", -] - -[[package]] -name = "ckb-script" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b4754a2f0ccea5ea1934822bd18a3a66c46344d8c3872cb20ffdcf0851fab9" -dependencies = [ - "byteorder", - "ckb-chain-spec", - "ckb-error", - "ckb-hash", - "ckb-logger", - "ckb-traits", - "ckb-types", - "ckb-vm", - "faster-hex", - "serde", -] - -[[package]] -name = "ckb-standalone-types" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22d7cbbdab96e6b809a102cf88bfec28795a0a3c06bfdea4abe4de89777801cd" -dependencies = [ - "cfg-if", - "molecule", -] - -[[package]] -name = "ckb-std" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a6ad40455c446ad6fbb303dae24827fc309f43558f59d1f1b863a9de3e9f81" -dependencies = [ - "buddy-alloc", - "cc", - "ckb-standalone-types", - "cstr_core", -] - -[[package]] -name = "ckb-system-scripts" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa5c59063142de7a68cfad4449c6b3863563856219a2925dfb8c5f019ec2aa47" -dependencies = [ - "blake2b-rs", - "faster-hex", - "includedir", - "includedir_codegen", - "phf", -] - -[[package]] -name = "ckb-systemtime" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243197680f69d6bb6cb1caf16199ce4a8162a258c757d5af8f727af0d8aabe9e" - -[[package]] -name = "ckb-testtool" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fed7e8aeb21e981246bc39e0bd49067f7734851798bef996389a3b02bf9b4e" -dependencies = [ - "ckb-always-success-script", - "ckb-chain-spec", - "ckb-crypto", - "ckb-error", - "ckb-hash", - "ckb-jsonrpc-types", - "ckb-resource", - "ckb-script", - "ckb-traits", - "ckb-types", - "ckb-verification", - "lazy_static", - "rand 0.7.3", -] - -[[package]] -name = "ckb-traits" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9d5827f20a396dfb785398db484fe50de93d76c02e1e32287832604a9dda91" -dependencies = [ - "ckb-types", -] - -[[package]] -name = "ckb-types" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c22b3b1ca8f88a8f48e2f73321c0605281c9c6f1e1c4d651c6138265c22291e" -dependencies = [ - "bit-vec", - "bytes", - "ckb-channel", - "ckb-error", - "ckb-fixed-hash", - "ckb-hash", - "ckb-merkle-mountain-range", - "ckb-occupied-capacity", - "ckb-rational", - "derive_more", - "merkle-cbt", - "molecule", - "numext-fixed-uint", - "once_cell", -] - -[[package]] -name = "ckb-util" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d165c6958601dfbfa4cd00c9263ecfb013b4ccb6d9e1d3187bfa62801abc7d" -dependencies = [ - "linked-hash-map", - "once_cell", - "parking_lot", - "regex", -] - -[[package]] -name = "ckb-verification" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc1745cf02f6d628ac04cf58145b853a359ad4d74fdb418207e99773185ad11" -dependencies = [ - "ckb-chain-spec", - "ckb-dao", - "ckb-dao-utils", - "ckb-error", - "ckb-pow", - "ckb-script", - "ckb-systemtime", - "ckb-traits", - "ckb-types", - "ckb-verification-traits", - "derive_more", - "lru", -] - -[[package]] -name = "ckb-verification-traits" -version = "0.108.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88de577410c2e72ccd18e00cb63fc0000d41be50604a895946a1566a02272730" -dependencies = [ - "bitflags", - "ckb-error", -] - -[[package]] -name = "ckb-vm" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1223acc8054ce96f91c5d99d4942898d0bdadd618c3b14f1acd3e67212991d8e" -dependencies = [ - "byteorder", - "bytes", - "cc", - "ckb-vm-definitions", - "derive_more", - "goblin 0.2.3", - "goblin 0.4.0", - "rand 0.7.3", - "scroll", - "serde", -] - -[[package]] -name = "ckb-vm-definitions" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af800ae2b6c54b70efa398dab015a09a52eeac2dd1ac3ad32c9bbe224974225" - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cpufeatures" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "eaglesong" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d978bd5d343e8ab9b5c0fc8d93ff9c602fdc96616ffff9c05ac7a155419b824" - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest", - "ff", - "generic-array", - "group", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "faster-hex" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e2ce894d53b295cf97b05685aa077950ff3e8541af83217fc720a6437169f8" - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "goblin" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20fd25aa456527ce4f544271ae4fea65d2eda4a6561ea56f39fb3ee4f7e3884" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "goblin" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532a09cd3df2c6bbfc795fb0434bff8f22255d1d07328180e918a2e6ce122d4d" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "heapsize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" -dependencies = [ - "winapi", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "includedir" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afd126bd778c00c43a9dc76d1609a0894bf4222088088b2217ccc0ce9e816db7" -dependencies = [ - "flate2", - "phf", -] - -[[package]] -name = "includedir_codegen" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ac1500c9780957c9808c4ec3b94002f35aab01483833f5a8bce7dfb243e3148" -dependencies = [ - "flate2", - "phf_codegen", - "walkdir", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", - "sha3", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.142" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -dependencies = [ - "serde", -] - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "merkle-cbt" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171d2f700835121c3b04ccf0880882987a050fd5c7ae88148abf537d33dd3a56" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "molecule" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc8276c02a006bddad7d1c28c1a88f30421e1b5f0ba0ca96ceb8077c7d20c01" -dependencies = [ - "bytes", - "cfg-if", - "faster-hex", -] - -[[package]] -name = "numext-constructor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "621fe0f044729f810c6815cdd77e8f5e0cd803ce4f6a38380ebfc1322af98661" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "numext-fixed-uint" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c68c76f96d589d1009a666c5072f37f3114d682696505f2cf445f27766c7d70" -dependencies = [ - "numext-fixed-uint-core", - "numext-fixed-uint-hack", -] - -[[package]] -name = "numext-fixed-uint-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aab1d6457b97b49482f22a92f0f58a2f39bdd7f3b2f977eae67e8bc206aa980" -dependencies = [ - "heapsize", - "numext-constructor", - "rand 0.7.3", - "serde", - "thiserror", -] - -[[package]] -name = "numext-fixed-uint-hack" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200f8d55c36ec1b6a8cf810115be85d4814f045e0097dfd50033ba25adb4c9e" -dependencies = [ - "numext-fixed-uint-core", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "perun-common" -version = "0.1.0" -dependencies = [ - "blake2b-rs", - "ckb-occupied-capacity", - "ckb-std", - "ckb-types", - "k256", - "molecule", -] - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared", - "rand 0.7.3", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.9", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scroll" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "subtle", - "zeroize", -] - -[[package]] -name = "secp256k1" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" -dependencies = [ - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" -dependencies = [ - "cc", -] - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "serde" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tests" -version = "0.1.0" -dependencies = [ - "ckb-occupied-capacity", - "ckb-standalone-types", - "ckb-std", - "ckb-testtool", - "hex", - "k256", - "molecule", - "perun-common", - "rand 0.8.5", - "rand_core 0.6.4", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/payment-channel-ckb/devnet/contracts/tests/Cargo.toml b/payment-channel-ckb/devnet/contracts/tests/Cargo.toml index 7d3dbcb..2df1d78 100644 --- a/payment-channel-ckb/devnet/contracts/tests/Cargo.toml +++ b/payment-channel-ckb/devnet/contracts/tests/Cargo.toml @@ -3,16 +3,18 @@ name = "tests" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +native-simulator = [ "ckb-testtool/native-simulator" ] [dependencies] -ckb-testtool = "0.9" +ckb-testtool = "0.15.0" +serde_json = "1.0" hex = "0.4.3" -rand = "0.8.5" -perun-common = { path = "../contracts/perun-common", default-features = false, features = ["testing"] } -molecule = "0.7.3" -ckb-types = { package = "ckb-standalone-types", version = "0.1.2" } -k256 = { version = "0.11.6", default-features = false, features = ["ecdsa", "arithmetic"]} +rand = "0.9.0" +perun-common = { path = "../crates/perun-common", default-features = false, features = ["testing"] } +molecule = "0.8.0" +ckb-types = { package = "ckb-gen-types", version = "0.200.0" } +k256 = { version = "0.13.4", default-features = false, features = ["ecdsa", "arithmetic"]} rand_core = { version = "0.6", features = ["getrandom"] } -ckb-std = "0.10.0" -ckb-occupied-capacity = "0.108.0" +ckb-std = "0.16.4" +ckb-occupied-capacity = "0.200.0" \ No newline at end of file diff --git a/payment-channel-ckb/devnet/contracts/tests/src/lib.rs b/payment-channel-ckb/devnet/contracts/tests/src/lib.rs index c58a205..c040b27 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/lib.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/lib.rs @@ -1,4 +1,11 @@ -use ckb_testtool::ckb_types::bytes::Bytes; +use ckb_testtool::{ + ckb_error::Error, + ckb_types::{ + bytes::Bytes, + core::{Cycle, TransactionView}, + }, + context::Context, +}; use std::env; use std::fs; use std::path::PathBuf; @@ -9,7 +16,9 @@ mod perun; #[cfg(test)] mod tests; -const TEST_ENV_VAR: &str = "CAPSULE_TEST_ENV"; +// The exact same Loader code from capsule's template, except that +// now we use MODE as the environment variable +const TEST_ENV_VAR: &str = "MODE"; pub enum TestEnv { Debug, @@ -34,7 +43,7 @@ impl Default for Loader { fn default() -> Self { let test_env = match env::var(TEST_ENV_VAR) { Ok(val) => val.parse().expect("test env"), - Err(_) => TestEnv::Debug, + Err(_) => TestEnv::Release, }; Self::with_test_env(test_env) } @@ -46,11 +55,28 @@ impl Loader { TestEnv::Debug => "debug", TestEnv::Release => "release", }; - let dir = env::current_dir().unwrap(); - let mut base_path = PathBuf::new(); - base_path.push(dir); - base_path.push(".."); - base_path.push("build"); + let mut base_path = match env::var("TOP") { + Ok(val) => { + let mut base_path: PathBuf = val.into(); + base_path.push("build"); + base_path + } + Err(_) => { + let mut base_path = PathBuf::new(); + // cargo may use a different cwd when running tests, for example: + // when running debug in vscode, it will use workspace root as cwd by default, + // when running test by `cargo test`, it will use tests directory as cwd, + // so we need a fallback path + base_path.push("build"); + if !base_path.exists() { + base_path.pop(); + base_path.push(".."); + base_path.push("build"); + } + base_path + } + }; + base_path.push(load_prefix); Loader(base_path) } @@ -61,3 +87,24 @@ impl Loader { fs::read(path).expect("binary").into() } } + +// This helper method runs Context::verify_tx, but in case error happens, +// it also dumps current transaction to failed_txs folder. +pub fn verify_and_dump_failed_tx( + context: &Context, + tx: &TransactionView, + max_cycles: u64, +) -> Result { + let result = context.verify_tx(tx, max_cycles); + if result.is_err() { + let mut path = env::current_dir().expect("current dir"); + path.push("failed_txs"); + std::fs::create_dir_all(&path).expect("create failed_txs dir"); + let mock_tx = context.dump_tx(tx).expect("dump failed tx"); + let json = serde_json::to_string_pretty(&mock_tx).expect("json"); + path.push(format!("0x{:x}.json", tx.hash())); + println!("Failed tx written to {:?}", path); + std::fs::write(path, json).expect("write"); + } + result +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs index 6f06ec9..45c4ded 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs @@ -14,7 +14,7 @@ pub struct TestAccount { } impl TestAccount { - pub fn new(sk: SigningKey, name: String) -> Self { + pub fn _new(sk: SigningKey, name: String) -> Self { Self { sk, name } } @@ -25,7 +25,7 @@ impl TestAccount { } } - pub fn id(&self) -> &str { + pub fn _id(&self) -> &str { &self.name } } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs index 266d0da..a5147a0 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs @@ -8,19 +8,28 @@ use ckb_testtool::{ use k256::ecdsa::VerifyingKey; use perun_common::{ ctrue, - perun_types::{ChannelConstants, ChannelStatus, ChannelState}, + perun_types::{ChannelConstants, ChannelState, ChannelStatus}, }; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Mutex; + use crate::perun::{ self, - test::{keys, Client}, + test::{keys, transaction, Client}, }; use crate::perun::{harness, test}; +use ckb_testtool::ckb_types::prelude::IntoHeaderView; use std::cmp::PartialEq; use std::collections::HashMap; use std::fmt::Debug; -use super::{test::cell::FundingCell, Account}; +use super::{ + test::cell::FundingCell, + virtual_channel::{IdxMapWithDirection, VirtualChannel}, + Account, +}; enum ActionValidity { Valid, @@ -50,7 +59,7 @@ where /// All available parties. parts: HashMap, /// The surrounding chain context. - ctx: &'a mut Context, + ctx: Rc>>, /// The intial test harness environment supplying all Perun specific /// contracts and functionality for deployment etc. env: &'a harness::Env, @@ -70,12 +79,16 @@ macro_rules! call_action { ($self:ident, $action:ident $(, $x:expr)*$(,)*) => ( { println!("calling action {} on {}", stringify!($action), $self.active_part.name()); + let ctx = match $self.ctx.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; let res = match $self.validity { - ActionValidity::Valid => $self.active_part.$action($self.ctx, $self.env, $($x),*), + ActionValidity::Valid => $self.active_part.$action(&mut ctx.borrow_mut(), $self.env, $($x),*), ActionValidity::Invalid => { - let res = $self.active_part.$action($self.ctx, $self.env, $($x),*); + let res = $self.active_part.$action(&mut ctx.borrow_mut(), $self.env, $($x),*); match res { - Ok(_) => Err(perun::Error::new("action should have failed")), + Ok(_) => Err(perun::Error::new("action should have failedaction should have failed")), Err(_) => Ok(Default::default()), } } @@ -91,7 +104,7 @@ where S: Default + perun::Applyable + Debug + PartialEq, { pub fn new( - context: &'a mut Context, + context: Rc>>, env: &'a perun::harness::Env, parts: &[perun::TestAccount], ) -> Self { @@ -153,6 +166,43 @@ where Ok(()) } + pub fn vc_start(&mut self, vc: &mut VirtualChannel) -> Result<(), perun::Error> { + let vcts = vc.vcts(); + let vc_status = vc.vc_status(); + self.channel_state = self + .channel_state + .clone() + .as_builder() + .disputed(ctrue!()) + .vc_disputed(ctrue!()) + .vcts_hash(vcts.calc_script_hash()) + .build(); + let lc_sigs = self.sigs_for_channel_state()?; + let vc_sigs = vc.sigs_for_vc_status()?; + let parent_args = transaction::DisputeArgs { + party_index: self.active_part.index, + channel_cell: self.channel_cell.clone().expect("no channel cell"), + state: self.channel_state.clone(), + sigs: lc_sigs, + pcts_script: self.pcts.clone(), + }; + + let result = call_action!( + self, + vc_start, + parent_args, + vc_status.clone(), + vc_sigs.clone(), + vcts.clone(), + )?; + self.push_header_with_cell(result.vc_cell.clone()); + vc.set_cell(result.vc_cell.clone()); + self.channel_cell = Some(result.parent_lc_cell.clone()); + self.push_header_with_cell(result.parent_lc_cell); + self.push_header_with_cell(result.vc_cell); + Ok(()) + } + fn push_header_with_cell(&mut self, cell: OutPoint) { let header = Header::new_builder() .raw( @@ -162,9 +212,15 @@ where ) .build() .into_view(); - self.ctx.insert_header(header.clone()); + let ctx = match self.ctx.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + ctx.borrow_mut().insert_header(header.clone()); // We will always use 0 as the `tx_index`. - self.ctx.link_cell_with_block(cell, header.hash(), 0); + ctx.borrow_mut() + .link_cell_with_block(cell, header.hash(), 0); + drop(ctx); } /// fund a channel using the currently active participant set by `with(..)` @@ -199,13 +255,18 @@ where /// to the given `to` participant. pub fn send(&mut self, to: &P, amount: u64) -> Result<(), perun::Error> { let to = self.parts.get(&to.name()).expect("part not found"); - self.active_part.send(self.ctx, self.env) + self.active_part.send(self.ctx.clone(), self.env) } /// dispute a channel using the currently active participant set by /// `with(..)`. pub fn dispute(&mut self) -> Result<(), perun::Error> { - self.channel_state = self.channel_state.clone().as_builder().disputed(ctrue!()).build(); + self.channel_state = self + .channel_state + .clone() + .as_builder() + .disputed(ctrue!()) + .build(); let sigs = self.sigs_for_channel_state()?; let res = match &self.channel_cell { Some(channel_cell) => { @@ -226,6 +287,119 @@ where Ok(()) } + //register dispute for second lc parent without update on vc + pub fn vc_progress_no_update(&mut self, vc: &mut VirtualChannel) -> Result<(), perun::Error> { + let vcts = vc.vcts(); + let vc_status = vc.vc_status(); + self.channel_state = self + .channel_state + .clone() + .as_builder() + .disputed(ctrue!()) + .vc_disputed(ctrue!()) + .vcts_hash(vcts.calc_script_hash()) + .build(); + let lc_sigs = self.sigs_for_channel_state()?; + let parent_args = transaction::DisputeArgs { + party_index: self.active_part.index, + channel_cell: self.channel_cell.clone().expect("no channel cell"), + state: self.channel_state.clone(), + sigs: lc_sigs, + pcts_script: self.pcts.clone(), + }; + + let result = call_action!( + self, + vc_progress_no_update, + parent_args, + vc.cell().clone(), + vc_status.clone(), + vcts.clone(), + )?; + self.channel_cell = Some(result.parent_cell.clone()); + vc.set_cell(result.vc_cell.clone()); + self.push_header_with_cell(result.parent_cell); + self.push_header_with_cell(result.vc_cell); + Ok(()) + } + + pub fn vc_update_only(&mut self, vc: &mut VirtualChannel) -> Result<(), perun::Error> { + let vcts = vc.vcts(); + let vc_status = vc.vc_status(); + let lc_sigs = self.sigs_for_channel_state()?; + let vc_sigs = vc.sigs_for_vc_status()?; + + let parent_args = transaction::DisputeArgs { + party_index: self.active_part.index, + channel_cell: self.channel_cell.clone().expect("no channel cell"), + state: self.channel_state.clone(), + sigs: lc_sigs, + pcts_script: self.pcts.clone(), + }; + let result = call_action!( + self, + vc_update_only, + parent_args, + vc.cell().clone(), + vc_status.clone(), + vc_sigs.clone(), + vcts.clone(), + )?; + self.channel_cell = Some(result.parent_cell.clone()); + vc.set_cell(result.vc_cell.clone()); + self.push_header_with_cell(result.parent_cell); + self.push_header_with_cell(result.vc_cell); + Ok(()) + } + + pub fn vc_lc_update(&mut self, vc: &mut VirtualChannel) -> Result<(), perun::Error> { + let vcts = vc.vcts(); + let vc_status = vc.vc_status(); + let lc_sigs = self.sigs_for_channel_state()?; + let vc_sigs = vc.sigs_for_vc_status()?; + let parent_args = transaction::DisputeArgs { + party_index: self.active_part.index, + channel_cell: self.channel_cell.clone().expect("no channel cell"), + state: self.channel_state.clone(), + sigs: lc_sigs, + pcts_script: self.pcts.clone(), + }; + let result = call_action!( + self, + vc_lc_update, + parent_args, + vc.cell().clone(), + vc_status.clone(), + vc_sigs.clone(), + vcts.clone(), + )?; + self.channel_cell = Some(result.parent_cell.clone()); + vc.set_cell(result.vc_cell.clone()); + self.push_header_with_cell(result.parent_cell); + self.push_header_with_cell(result.vc_cell); + Ok(()) + } + + pub fn vc_merge( + &mut self, + vc1: &VirtualChannel, + vc2: &VirtualChannel, + idx: u8, + ) -> Result { + let result = call_action!( + self, + vc_merge, + vc1.cell().clone(), + vc2.cell().clone(), + vc1.vc_status().clone(), + vc2.vc_status().clone(), + vc1.vcts().clone(), + idx, + )?; + self.push_header_with_cell(result.final_vc_cell.clone()); + Ok(result.final_vc_cell) + } + /// abort a channel using the currently active participant set by /// `with(..)`. pub fn abort(&mut self) -> Result<(), perun::Error> { @@ -250,14 +424,23 @@ where pub fn finalize(&mut self) -> &mut Self { let status = self.channel_state.clone(); let old_version: u64 = status.state().version().unpack(); - let state = status.state().as_builder().is_final(ctrue!()).version((old_version + 1).pack()).build(); + let state = status + .state() + .as_builder() + .is_final(ctrue!()) + .version((old_version + 1).pack()) + .build(); self.channel_state = status.as_builder().state(state).build(); self } - pub fn update(&mut self, update: impl Fn(&ChannelState) -> Result) -> &mut Self { + pub fn update( + &mut self, + update: impl Fn(&ChannelState) -> Result, + ) -> &mut Self { let new_state = update(&self.channel_state.state()).expect("update failed"); - self.channel_state = self.channel_state + self.channel_state = self + .channel_state .clone() .as_builder() .state(new_state) @@ -330,7 +513,9 @@ where .into_view(); // Push a header with the current time which can be used in force_close // as for time validation purposes. - self.ctx.insert_header(h.clone()); + let ctx = self.ctx.lock().unwrap(); + ctx.borrow_mut().insert_header(h.clone()); + drop(ctx); match self.channel_cell.clone() { Some(channel_cell) => call_action!( self, @@ -345,6 +530,92 @@ where Ok(()) } + pub fn vc_close1( + &mut self, + vc: &mut VirtualChannel, + idx_map: &IdxMapWithDirection, + ) -> Result<(), perun::Error> { + let h = Header::new_builder() + .raw( + RawHeader::new_builder() + .timestamp(self.current_time.pack()) + .build(), + ) + .build() + .into_view(); + let vc_status = vc + .vc_status() + .clone() + .as_builder() + .first_force_close(ctrue!()) + .build(); + // Push a header with the current time which can be used in force_close + // as for time validation purposes. + let ctx = match self.ctx.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + ctx.borrow_mut().insert_header(h.clone()); + drop(ctx); + let result = match &self.channel_cell { + Some(channel_cell) => call_action!( + self, + vc_close1, + self.id, + channel_cell.clone(), + self.funding_cells.clone(), + self.channel_state.clone(), + vc.cell().clone(), + vc_status, + idx_map.clone(), + vc.vcts().clone(), + ), + None => panic!("no channel cell, invalid test setup"), + }?; + self.push_header_with_cell(result.output_vc_cell.clone()); + vc.set_cell(result.output_vc_cell.clone()); + Ok(()) + } + + pub fn vc_close2( + &mut self, + vc: &mut VirtualChannel, + idx_map: &IdxMapWithDirection, + ) -> Result<(), perun::Error> { + let h = Header::new_builder() + .raw( + RawHeader::new_builder() + .timestamp(self.current_time.pack()) + .build(), + ) + .build() + .into_view(); + // Push a header with the current time which can be used in force_close + // as for time validation purposes. + let ctx = match self.ctx.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + ctx.borrow_mut().insert_header(h.clone()); + drop(ctx); + match &self.channel_cell { + Some(channel_cell) => call_action!( + self, + vc_close2, + self.id, + channel_cell.clone(), + self.funding_cells.clone(), + self.channel_state.clone(), + vc.cell().clone(), + vc.vc_status().clone(), + idx_map.clone(), + vc.vcts().clone(), + ), + None => panic!("no channel cell, invalid test setup"), + }?; + Ok(()) + } + /// valid sets the validity of the next action to valid. (default) pub fn valid(&mut self) -> &mut Self { self.validity = ActionValidity::Valid; @@ -371,4 +642,12 @@ where .fold(Default::default(), |acc, act| acc.apply(act)); assert_eq!(expected_state, self.current_state) } + + pub fn channel_state(&self) -> &ChannelStatus { + &self.channel_state + } + + pub fn pcts(&self) -> &Script { + &self.pcts + } } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs index 4e288fc..791958c 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs @@ -6,21 +6,29 @@ use ckb_testtool::{ ckb_types::{bytes::Bytes, packed::*, prelude::*}, context::Context, }; -use perun_common::cfalse; -use perun_common::perun_types::ChannelStateBuilder; -use perun_common::perun_types::ChannelStatusBuilder; -use perun_common::perun_types::{self, ChannelStatus, ChannelToken}; +use ckb_types::core::ScriptHashType; +use perun_common::perun_types::{ + self, ChannelStateBuilder, ChannelStatus, ChannelStatusBuilder, ChannelToken, ParentsVec, + Participant, VirtualChannelStatus, VirtualChannelStatusBuilder, +}; +use perun_common::{cfalse, ctrue}; use super::test::ChannelId; use super::test::FundingAgreement; use super::test::FundingAgreementEntry; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Mutex; + // Env contains all chain information required for running Perun // tests. pub struct Env { // Perun contracts. pub pcls_out_point: OutPoint, pub pcts_out_point: OutPoint, + pub vcls_out_point: OutPoint, + pub vcts_out_point: OutPoint, pub pfls_out_point: OutPoint, // Auxiliary contracts. pub always_success_out_point: OutPoint, @@ -29,9 +37,14 @@ pub struct Env { // Perun scripts. pcls_script: Script, pcts_script: Script, + vcls_script: Script, + vcts_script: Script, pfls_script: Script, + pub pcls_script_dep: CellDep, pub pcts_script_dep: CellDep, + pub vcls_script_dep: CellDep, + pub vcts_script_dep: CellDep, pub pfls_script_dep: CellDep, // Auxiliary scripts. pub always_success_script: Script, @@ -50,55 +63,110 @@ impl Env { // prepare_env prepares the given context to be used for running Perun // tests. pub fn new( - context: &mut Context, + ctx: Rc>>, max_cycles: u64, challenge_duration: u64, ) -> Result { + let context = ctx.lock().unwrap(); // Perun contracts. let pcls: Bytes = Loader::default().load_binary("perun-channel-lockscript"); let pcts: Bytes = Loader::default().load_binary("perun-channel-typescript"); + let vcls: Bytes = Loader::default().load_binary("perun-vchannel-lockscript"); + let vcts: Bytes = Loader::default().load_binary("perun-vchannel-typescript"); let pfls: Bytes = Loader::default().load_binary("perun-funds-lockscript"); let sample_udt: Bytes = Loader::default().load_binary("sample-udt"); + println!("the same? {:?}", pfls == sample_udt); // Deploying the contracts returns the cell they are deployed in. - let pcls_out_point = context.deploy_cell(pcls); - let pcts_out_point = context.deploy_cell(pcts); - let pfls_out_point = context.deploy_cell(pfls); - let sample_udt_out_point = context.deploy_cell(sample_udt); + let pcls_out_point = context.borrow_mut().deploy_cell(pcls); + let pcts_out_point = context.borrow_mut().deploy_cell(pcts); + let vcls_out_point = context.borrow_mut().deploy_cell(vcls); + let vcts_out_point = context.borrow_mut().deploy_cell(vcts); + let pfls_out_point = context.borrow_mut().deploy_cell(pfls); + let sample_udt_out_point = context.borrow_mut().deploy_cell(sample_udt); // Auxiliary contracts. - let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); + let always_success_out_point = context.borrow_mut().deploy_cell(ALWAYS_SUCCESS.clone()); // Prepare scripts. // Perun scripts. let pcls_script = context - .build_script(&pcls_out_point, Default::default()) + .borrow_mut() + .build_script_with_hash_type(&pcls_out_point, ScriptHashType::Data1, Default::default()) .ok_or("perun-channel-lockscript")?; + println!( + "Built pcls_script: code_hash = {:?}, hash_type = {:?}", + pcls_script.code_hash(), + pcls_script.hash_type() + ); let pcts_script = context - .build_script( + .borrow_mut() + .build_script_with_hash_type( &pcts_out_point, + ScriptHashType::Data1, perun_types::ChannelConstants::default().as_bytes(), ) .ok_or("perun-channel-typescript")?; + println!( + "Built pcts_script: code_hash = {:?}, hash_type = {:?}", + pcts_script.code_hash(), + pcts_script.hash_type() + ); + let vcls_script = context + .borrow_mut() + .build_script(&vcls_out_point, Default::default()) + .ok_or("perun-virtual-channel-lockscript")?; + let vcts_script = context + .borrow_mut() + .build_script( + &vcts_out_point, + perun_types::ChannelConstants::default().as_bytes(), + ) + .ok_or("perun-virtual-channel-typescript")?; let pfls_script = context - .build_script(&pfls_out_point, Default::default()) + .borrow_mut() + .build_script_with_hash_type(&pfls_out_point, ScriptHashType::Data1, Default::default()) .ok_or("perun-funds-lockscript")?; + println!( + "Built pfls_script: code_hash = {:?}, hash_type = {:?}", + pfls_script.code_hash(), + pfls_script.hash_type() + ); let sample_udt_script = context - .build_script(&sample_udt_out_point, Default::default()) + .borrow_mut() + .build_script_with_hash_type( + &sample_udt_out_point, + ScriptHashType::Data1, + Default::default(), + ) .ok_or("sample-udt")?; + println!( + "Built sample_udt_script: code_hash = {:?}, hash_type = {:?}", + sample_udt_script.code_hash(), + sample_udt_script.hash_type() + ); let pcls_script_dep = CellDep::new_builder() .out_point(pcls_out_point.clone()) .build(); let pcts_script_dep = CellDep::new_builder() .out_point(pcts_out_point.clone()) .build(); + let vcls_script_dep = CellDep::new_builder() + .out_point(vcls_out_point.clone()) + .build(); + let vcts_script_dep = CellDep::new_builder() + .out_point(vcts_out_point.clone()) + .build(); let pfls_script_dep = CellDep::new_builder() .out_point(pfls_out_point.clone()) .build(); let sample_udt_script_dep = CellDep::new_builder() .out_point(sample_udt_out_point.clone()) .build(); - let sample_udt_max_cap = sample_udt_script.occupied_capacity()?.safe_mul(Capacity::shannons(10))?; + let sample_udt_max_cap = sample_udt_script + .occupied_capacity()? + .safe_mul(Capacity::shannons(10))?; // Auxiliary scripts. let always_success_script = context + .borrow_mut() .build_script(&always_success_out_point, Bytes::from(vec![0])) .expect("always_success"); let always_success_script_dep = CellDep::new_builder() @@ -123,18 +191,27 @@ impl Env { println!("asset code hash: {}", sample_udt_script.code_hash()); println!("pcts code hash: {}", pcts_script.code_hash()); println!("pcls code hash: {}", pcls_script.code_hash()); - println!("always_success code hash: {}", always_success_script.code_hash()); + println!( + "always_success code hash: {}", + always_success_script.code_hash() + ); Ok(Env { pcls_out_point, pcts_out_point, + vcls_out_point, + vcts_out_point, pfls_out_point, always_success_out_point, sample_udt_out_point, pcls_script, pcts_script, + vcls_script, + vcts_script, pfls_script, pcls_script_dep, pcts_script_dep, + vcls_script_dep, + vcts_script_dep, pfls_script_dep, always_success_script, always_success_script_dep, @@ -151,21 +228,36 @@ impl Env { pub fn build_pcls(&self, context: &mut Context, args: Bytes) -> Script { let pcls_out_point = &self.pcls_out_point; context - .build_script(pcls_out_point, args) + .build_script_with_hash_type(pcls_out_point, ScriptHashType::Data1, args) .expect("perun-channel-lockscript") } pub fn build_pcts(&self, context: &mut Context, args: Bytes) -> Script { let pcts_out_point = &self.pcts_out_point; context - .build_script(pcts_out_point, args) + .build_script_with_hash_type(pcts_out_point, ScriptHashType::Data1, args) .expect("perun-channel-typescript") } + pub fn build_vcls(&self, context: &mut Context, args: Bytes) -> Script { + let vcls_out_point = &self.vcls_out_point; + context + .build_script(vcls_out_point, args) + .expect("perun-virtual-channel-lockscript") + } + + pub fn build_vcts(&self, context: &mut Context, args: Bytes) -> Script { + let vcts_out_point = &self.vcts_out_point; + let result = context.build_script(vcts_out_point, args); + let script_hash = result.clone().unwrap().calc_script_hash(); + println!("Debug: vcts script hash = {:?}", script_hash); + result.expect("Cannot build vcts") + } + pub fn build_pfls(&self, context: &mut Context, args: Bytes) -> Script { let pfls_out_point = &self.pfls_out_point; context - .build_script(pfls_out_point, args) + .build_script_with_hash_type(pfls_out_point, ScriptHashType::Data1, args) .expect("perun-funds-lockscript") } @@ -187,6 +279,20 @@ impl Env { Ok(min_capacity) } + pub fn min_capacity_for_vc_channel( + &self, + vcs: VirtualChannelStatus, + ) -> Result { + let tmp_output = CellOutput::new_builder() + .capacity(0u64.pack()) + .lock(self.vcls_script.clone()) + .type_(Some(self.vcts_script.clone()).pack()) + .build(); + let vcs_capacity = Capacity::bytes(vcs.as_bytes().len())?; + let min_capacity = tmp_output.occupied_capacity(vcs_capacity)?; + Ok(min_capacity) + } + pub fn create_channel_token(&self, context: &mut Context) -> (ChannelToken, OutPoint) { let channel_token_outpoint = context.create_cell( CellOutput::new_builder() @@ -215,8 +321,19 @@ impl Env { party_index: u8, funding_agreement: &FundingAgreement, ) -> Result, perun::Error> { - let mut funds = self.create_ckbytes_funds_for_index(context, party_index, funding_agreement.expected_ckbytes_funding_for(party_index)?)?; - funds.append(self.create_sudts_funds_for_index(context, party_index, funding_agreement.expected_sudts_funding_for(party_index)?)?.as_mut()); + let mut funds = self.create_ckbytes_funds_for_index( + context, + party_index, + funding_agreement.expected_ckbytes_funding_for(party_index)?, + )?; + funds.append( + self.create_sudts_funds_for_index( + context, + party_index, + funding_agreement.expected_sudts_funding_for(party_index)?, + )? + .as_mut(), + ); return Ok(funds); } @@ -236,7 +353,12 @@ impl Env { Ok(vec![(cell, required_funds.into_capacity())]) } - pub fn create_sudts_funds_for_index(&self, context: &mut Context, party_index: u8, required_funds: Vec<(Script, Capacity, u128)>) -> Result, perun::Error> { + pub fn create_sudts_funds_for_index( + &self, + context: &mut Context, + party_index: u8, + required_funds: Vec<(Script, Capacity, u128)>, + ) -> Result, perun::Error> { let mut outs: Vec<(OutPoint, Capacity)> = Vec::new(); for (sudt_script, capacity, amount) in required_funds { let my_output = CellOutput::new_builder() @@ -245,16 +367,26 @@ impl Env { .lock(self.build_lock_script(context, Bytes::from(vec![party_index]))) .type_(Some(sudt_script).pack()) .build(); - let cell = context.create_cell(my_output.clone(), Bytes::from(amount.to_le_bytes().to_vec())); + let cell = context.create_cell( + my_output.clone(), + Bytes::from(amount.to_le_bytes().to_vec()), + ); outs.push((cell, capacity)); } Ok(outs) } pub fn create_min_cell_for_index(&self, context: &mut Context, party_index: u8) -> OutPoint { - self.create_ckbytes_funds_for_index(context, party_index, self.min_capacity_no_script.as_u64()) - .unwrap() - .get(0).unwrap().clone().0 + self.create_ckbytes_funds_for_index( + context, + party_index, + self.min_capacity_no_script.as_u64(), + ) + .unwrap() + .get(0) + .unwrap() + .clone() + .0 } pub fn build_initial_channel_state( @@ -279,7 +411,50 @@ impl Env { .state(channel_state) .funded(cfalse!()) .disputed(cfalse!()) + .vc_disputed(cfalse!()) .build(); Ok(channel_status) } + + pub fn build_virtual_channel_state( + &self, + channel_id: &ChannelId, + funding_agreement: &FundingAgreement, + parents: &ParentsVec, + first_force_close: bool, + owner: Participant, + ) -> Result { + let all_indices = funding_agreement + .content() + .iter() + .map(|FundingAgreementEntry { index, .. }| *index) + .collect::>(); + let channel_balances = funding_agreement.mk_balances(all_indices)?; + let channel_state = ChannelStateBuilder::default() + .channel_id(channel_id.to_byte32()) + .balances(channel_balances) + .version(Default::default()) + .is_final(cfalse!()) + .build(); + + let flag = match first_force_close { + true => ctrue!(), + false => cfalse!(), + }; + let vc_status = VirtualChannelStatusBuilder::default() + .vcstate(channel_state) + .parents(parents.clone()) + .first_force_close(flag) + .owner(owner) + .build(); + Ok(vc_status) + } + + pub fn get_vcts(&self) -> &Script { + &self.vcts_script + } + + pub fn get_vcls_(&self) -> &Script { + &self.vcls_script + } } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs index cbf1768..ed184be 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs @@ -20,3 +20,5 @@ pub mod random; mod account; pub use account::*; + +pub mod virtual_channel; diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs index 24abb8c..f32b4c2 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs @@ -1,7 +1,7 @@ use crate::perun; -use ckb_testtool::ckb_types::prelude::{Unpack, Pack}; -use molecule::prelude::{Entity, Builder}; -use perun_common::perun_types::{ChannelState, CKByteDistribution, SUDTDistribution}; +use ckb_testtool::ckb_types::prelude::{Pack, Unpack}; +use molecule::prelude::{Builder, Entity}; +use perun_common::perun_types::{CKByteDistribution, ChannelState, SUDTDistribution}; pub enum Direction { AtoB, @@ -15,12 +15,20 @@ pub fn id() -> impl Fn(&ChannelState) -> Result { /// bump_version returns a mutator that bumps the version number of the channel state. pub fn bump_version() -> impl Fn(&ChannelState) -> Result { - |s| Ok(s.clone().as_builder().version((Unpack::::unpack(&s.version()) + 1u64).pack()).build()) + |s| { + Ok(s.clone() + .as_builder() + .version((Unpack::::unpack(&s.version()) + 1u64).pack()) + .build()) + } } /// pay_ckbytes returns a mutator that transfers the given amount of CKBytes from one party to the other according to the /// specified direction. It also bumps the version number of the channel state. -pub fn pay_ckbytes(direction: Direction, amount: u64) -> impl Fn(&ChannelState) -> Result { +pub fn pay_ckbytes( + direction: Direction, + amount: u64, +) -> impl Fn(&ChannelState) -> Result { let (sender_index, receiver_index) = get_indices(direction); move |s| { let s_bumped = bump_version()(s)?; @@ -30,14 +38,23 @@ pub fn pay_ckbytes(direction: Direction, amount: u64) -> impl Fn(&ChannelState) } distribution[sender_index] -= amount; distribution[receiver_index] += amount; - let balances = s_bumped.balances().clone().as_builder().ckbytes(CKByteDistribution::from_array(distribution)).build(); + let balances = s_bumped + .balances() + .clone() + .as_builder() + .ckbytes(CKByteDistribution::from_array(distribution)) + .build(); Ok(s_bumped.clone().as_builder().balances(balances).build()) } } /// pay_sudt returns a mutator that transfers the given amount of the specified SUDT index from one party to the other according to the /// specified direction. It also bumps the version number of the channel state. -pub fn pay_sudt(direction:Direction, amount: u128, asset_index: usize)-> impl Fn(&ChannelState) -> Result { +pub fn pay_sudt( + direction: Direction, + amount: u128, + asset_index: usize, +) -> impl Fn(&ChannelState) -> Result { let (sender_index, receiver_index) = get_indices(direction); move |s| { let s_bumped = bump_version()(s)?; @@ -52,10 +69,19 @@ pub fn pay_sudt(direction:Direction, amount: u128, asset_index: usize)-> impl Fn } distribution[sender_index] -= amount; distribution[receiver_index] += amount; - let packed_sudt = sudt.clone().as_builder().distribution(SUDTDistribution::from_array(distribution)).build(); + let packed_sudt = sudt + .clone() + .as_builder() + .distribution(SUDTDistribution::from_array(distribution)) + .build(); let mut new_sudts = sudts.clone().as_builder(); new_sudts.replace(asset_index, packed_sudt).unwrap(); - let balances = s_bumped.balances().clone().as_builder().sudts(new_sudts.build()).build(); + let balances = s_bumped + .balances() + .clone() + .as_builder() + .sudts(new_sudts.build()) + .build(); Ok(s_bumped.clone().as_builder().balances(balances).build()) } } @@ -66,4 +92,4 @@ fn get_indices(direction: Direction) -> (usize, usize) { Direction::AtoB => (0, 1), Direction::BtoA => (1, 0), } -} \ No newline at end of file +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/cell.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/cell.rs index 668d262..58944c5 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/cell.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/cell.rs @@ -1,10 +1,12 @@ -use ckb_testtool::{ckb_types::{packed::{OutPoint, CellOutput}, prelude::{Unpack, Pack}}}; +use ckb_testtool::ckb_types::{ + packed::{CellOutput, OutPoint}, + prelude::{Pack, Unpack}, +}; use ckb_types::bytes; -use molecule::prelude::{Entity, Builder}; +use molecule::prelude::{Builder, Entity}; use super::{Asset, AssetRegister}; - #[derive(Debug, Clone)] pub enum FundingCell { @@ -44,9 +46,17 @@ impl Default for FundingCell { } } -pub fn mk_funding_cell(party_index: u8, out_point: OutPoint, cell_output: &CellOutput, data: bytes::Bytes, register: &AssetRegister) -> FundingCell { - if cell_output.type_().is_some(){ - let asset = register.guess_asset_from_script(&cell_output.type_().to_opt().unwrap()).unwrap(); +pub fn mk_funding_cell( + party_index: u8, + out_point: OutPoint, + cell_output: &CellOutput, + data: bytes::Bytes, + register: &AssetRegister, +) -> FundingCell { + if cell_output.type_().is_some() { + let asset = register + .guess_asset_from_script(&cell_output.type_().to_opt().unwrap()) + .unwrap(); FundingCell::FundingCellSUDT(FundingCellSUDT { index: party_index, cap: cell_output.capacity().unpack(), @@ -61,7 +71,6 @@ pub fn mk_funding_cell(party_index: u8, out_point: OutPoint, cell_output: &CellO out_point, }) } - } impl FundingCell { @@ -71,4 +80,4 @@ impl FundingCell { FundingCell::FundingCellSUDT(f) => f.out_point.clone(), } } -} \ No newline at end of file +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/channel_id.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/channel_id.rs index 3b0f445..b1ba8b3 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/channel_id.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/channel_id.rs @@ -12,7 +12,7 @@ impl ChannelId { ChannelId(Default::default()) } - pub fn new_random() -> Self { + pub fn _new_random() -> Self { ChannelId(rand::thread_rng().gen()) } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/client.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/client.rs index cdc8aec..c3ccc02 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/client.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/client.rs @@ -9,23 +9,33 @@ use k256::ecdsa::signature::hazmat::PrehashSigner; use perun_common::*; use perun_common::helpers::blake2b256; -use perun_common::perun_types::{ChannelState, ChannelStatus}; +use perun_common::perun_types::{ChannelState, ChannelStatus, VirtualChannelStatus}; use crate::perun; use crate::perun::harness; use crate::perun::random; use crate::perun::test; -use crate::perun::test::transaction::{AbortArgs, OpenResult}; +use crate::perun::test::transaction::{ + mk_vc_lc_update, mk_vc_merge, mk_vc_progress_no_update, mk_vc_update_only, AbortArgs, + OpenResult, VCLCUpdateArgs, VCMergeArgs, VCProgressNoUpdateArgs, VCStartArgs, VCUpdateOnlyArgs, +}; use crate::perun::test::{keys, transaction}; use k256::ecdsa::{Signature, SigningKey}; use super::cell::FundingCell; +use super::transaction::{ + VCLCUpdateResult, VCMergeResult, VCProgressNoUpdateResult, VCUpdateOnlyResult, +}; use super::ChannelId; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Mutex; + #[derive(Clone, Debug)] pub struct Client { - index: u8, + pub index: u8, signing_key: SigningKey, name: String, } @@ -56,8 +66,7 @@ impl Client { funding_agreement: &test::FundingAgreement, ) -> Result<(ChannelId, OpenResult), perun::Error> { // Prepare environment so that this party has the required funds. - let inputs = - env.create_funds_from_agreement(ctx, self.index, funding_agreement)?; + let inputs = env.create_funds_from_agreement(ctx, self.index, funding_agreement)?; // Create the channel token. let (channel_token, channel_token_outpoint) = env.create_channel_token(ctx); @@ -66,9 +75,6 @@ impl Client { let pfls_code_hash = ctx .get_cell_data_hash(&env.pfls_out_point) .expect("pfls hash"); - let always_success_hash = ctx - .get_cell_data_hash(&env.always_success_out_point) - .expect("always success hash"); let parties = funding_agreement.mk_participants(ctx, env, env.min_capacity_no_script); @@ -124,8 +130,7 @@ impl Client { pcts: Script, ) -> Result { // Prepare environment so that this party has the required funds. - let inputs = - env.create_funds_from_agreement(ctx, self.index, funding_agreement)?; + let inputs = env.create_funds_from_agreement(ctx, self.index, funding_agreement)?; let fr = transaction::mk_fund( ctx, env, @@ -143,14 +148,18 @@ impl Client { Ok(fr) } - pub fn send(&self, ctx: &mut Context, env: &harness::Env) -> Result<(), perun::Error> { + pub fn send( + &self, + _ctx: Rc>>, + _env: &harness::Env, + ) -> Result<(), perun::Error> { Ok(()) } pub fn sign(&self, state: ChannelState) -> Result, perun::Error> { let s: Signature = self .signing_key - .sign_prehash(&blake2b256(state.as_slice()))?; + .sign_prehash(&perun_common::sig::ethereum_message_hash(state.as_slice()))?; Ok(Vec::from(s.to_der().as_bytes())) } @@ -180,6 +189,141 @@ impl Client { Ok(dr) } + pub fn vc_start( + &self, + ctx: &mut Context, + env: &harness::Env, + lc_dispute_args: transaction::DisputeArgs, + vc_status: VirtualChannelStatus, + sigs: [Vec; 2], + vcts: Script, + ) -> Result { + let vcsr = transaction::mk_vc_start( + ctx, + env, + VCStartArgs { + parent_args: lc_dispute_args, + vc_status: vc_status, + sigs: sigs, + vcts_script: vcts, + party_index: self.index, + }, + )?; + let cycles = ctx.verify_tx(&vcsr.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vcsr) + } + + pub fn vc_progress_no_update( + &self, + ctx: &mut Context, + env: &harness::Env, + lc_dispute_args: transaction::DisputeArgs, + vc_cell: OutPoint, + vc_status: VirtualChannelStatus, + vcts_script: Script, + ) -> Result { + let vcp_no_update = mk_vc_progress_no_update( + ctx, + env, + VCProgressNoUpdateArgs { + parent_args: lc_dispute_args, + vc_cell: vc_cell, + vc_status: vc_status, + vcts_script: vcts_script, + party_index: self.index, + }, + )?; + let cycles = ctx.verify_tx(&vcp_no_update.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vcp_no_update) + } + + pub fn vc_update_only( + &self, + ctx: &mut Context, + env: &harness::Env, + lc_dispute_args: transaction::DisputeArgs, + vc_cell: OutPoint, + vc_status: VirtualChannelStatus, + vc_sigs: [Vec; 2], + vcts_script: Script, + ) -> Result { + //make tx + let vc_update_only_result = mk_vc_update_only( + ctx, + env, + VCUpdateOnlyArgs { + parent_args: lc_dispute_args, + vc_cell: vc_cell, + vc_status: vc_status, + sigs: vc_sigs, + vcts_script: vcts_script, + party_index: self.index, + }, + )?; + let cycles = ctx.verify_tx(&vc_update_only_result.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vc_update_only_result) + } + + pub fn vc_lc_update( + &self, + ctx: &mut Context, + env: &harness::Env, + lc_dispute_args: transaction::DisputeArgs, + vc_cell: OutPoint, + vc_status: VirtualChannelStatus, + vc_sigs: [Vec; 2], + vcts_script: Script, + ) -> Result { + //make tx + let vc_lc_result = mk_vc_lc_update( + ctx, + env, + VCLCUpdateArgs { + parent_args: lc_dispute_args, + vc_cell: vc_cell, + vc_status: vc_status, + sigs: vc_sigs, + vcts_script: vcts_script, + party_index: self.index, + }, + )?; + let cycles = ctx.verify_tx(&vc_lc_result.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vc_lc_result) + } + + pub fn vc_merge( + &self, + ctx: &mut Context, + env: &harness::Env, + vc_cell1: OutPoint, + vc_cell2: OutPoint, + vc_status1: VirtualChannelStatus, + vc_status2: VirtualChannelStatus, + vcts_script: Script, + index: u8, + ) -> Result { + //make tx + let vc_merge_result = mk_vc_merge( + ctx, + env, + VCMergeArgs { + vc_cell1: vc_cell1, + vc_cell2: vc_cell2, + party_index: index, + vc_status1: vc_status1, + vc_status2: vc_status2, + vcts_script: vcts_script, + }, + )?; + let cycles = ctx.verify_tx(&vc_merge_result.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vc_merge_result) + } + pub fn abort( &self, ctx: &mut Context, @@ -256,4 +400,76 @@ impl Client { println!("consumed cycles: {}", cycles); Ok(fcr) } + + pub fn vc_close1( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + parent_cell: OutPoint, + fund_cells: Vec, + parent_state: ChannelStatus, + vc_cell: OutPoint, + vc_status: VirtualChannelStatus, + idx_map: perun::virtual_channel::IdxMapWithDirection, + vcts: Script, + ) -> Result { + let hs = ctx.headers.keys().cloned().collect(); + let vcc1r = transaction::mk_vc_close1( + ctx, + env, + transaction::VCClose1Args { + parent_args: transaction::ForceCloseArgs { + channel_cell: parent_cell, + headers: hs, + funds_cells: fund_cells, + state: parent_state, + party_index: self.index, + }, + vc_cell: vc_cell, + vc_status: vc_status, + idx_map_with_direction: idx_map, + vcts_script: vcts, + }, + )?; + let cycles = ctx.verify_tx(&vcc1r.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vcc1r) + } + + pub fn vc_close2( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + parent_cell: OutPoint, + fund_cells: Vec, + parent_state: ChannelStatus, + vc_cell: OutPoint, + vc_status: VirtualChannelStatus, + idx_map: perun::virtual_channel::IdxMapWithDirection, + vcts: Script, + ) -> Result { + let hs = ctx.headers.keys().cloned().collect(); + let vcc2r = transaction::mk_vc_close2( + ctx, + env, + transaction::VCClose2Args { + parent_args: transaction::ForceCloseArgs { + channel_cell: parent_cell, + headers: hs, + funds_cells: fund_cells, + state: parent_state, + party_index: self.index, + }, + vc_cell: vc_cell, + vc_status: vc_status, + idx_map_with_direction: idx_map, + vcts_script: vcts, + }, + )?; + let cycles = ctx.verify_tx(&vcc2r.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(vcc2r) + } } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/funding_agreement.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/funding_agreement.rs index 5723b99..1f47926 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/funding_agreement.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/funding_agreement.rs @@ -6,12 +6,13 @@ use ckb_types::bytes::Bytes; use k256::elliptic_curve::sec1::ToEncodedPoint; use k256::PublicKey; use perun_common::perun_types::{ - self, Balances, CKByteDistribution, ParticipantBuilder, - SEC1EncodedPubKeyBuilder, SUDTAllocation, SUDTAsset, SUDTBalances, SUDTDistribution, + self, Balances, CKByteDistribution, LockedBalances, ParticipantBuilder, + SEC1EncodedPubKeyBuilder, SUDTAllocation, SUDTAsset, SUDTBalances, SUDTDistribution, SubAlloc, + SubBalances, }; use crate::perun; - +use crate::perun::test::ChannelId; #[derive(Debug, Clone)] pub struct FundingAgreement { entries: Vec, @@ -170,6 +171,54 @@ impl FundingAgreement { .build()) } + pub fn mk_locked_balances(&self, id: ChannelId) -> Result { + let mut ckbytes = [0u64; 2]; + let sudts = self.register.get_sudtassets(); + let mut sudt_dist: Vec<[u128; 2]> = Vec::new(); + for _ in 0..sudts.len() { + sudt_dist.push([0u128, 0]); + } + for fae in self.entries.iter() { + ckbytes[fae.index as usize] = fae.ckbytes; + for (asset, amount) in fae.sudts.iter() { + sudt_dist[asset.0 as usize][fae.index as usize] = *amount; + } + } + let mut sudt_alloc: Vec = Vec::new(); + for (i, asset) in sudts.iter().enumerate() { + sudt_alloc.push( + SUDTBalances::new_builder() + .asset(asset.clone()) + .distribution( + SUDTDistribution::new_builder() + .nth0(sudt_dist[i][0].pack()) + .nth1(sudt_dist[i][1].pack()) + .build(), + ) + .build(), + ); + } + + let sub_balances = SubBalances::new_builder() + .ckbytes( + CKByteDistribution::new_builder() + .nth0(ckbytes[0].pack()) + .nth1(ckbytes[1].pack()) + .build(), + ) + .sudts(SUDTAllocation::new_builder().set(sudt_alloc).build()) + .build(); + + Ok(LockedBalances::new_builder() + .push( + SubAlloc::new_builder() + .id(id.to_byte32()) + .balances(sub_balances) + .build(), + ) + .build()) + } + pub fn expected_ckbytes_funding_for(&self, index: u8) -> Result { let entry = self .entries @@ -180,9 +229,12 @@ impl FundingAgreement { } pub fn sudt_max_cap_sum(&self) -> u64 { - self.register.get_sudtassets().iter().fold(0u64, |old, asset| { - old + Capacity::shannons(asset.max_capacity().unpack()).as_u64() - }) + self.register + .get_sudtassets() + .iter() + .fold(0u64, |old, asset| { + old + Capacity::shannons(asset.max_capacity().unpack()).as_u64() + }) } pub fn expected_sudts_funding_for( @@ -219,7 +271,7 @@ pub struct FundingAgreementEntry { pub struct Asset(pub u32); impl Asset { - pub fn new() -> Self { + pub fn _new() -> Self { Asset(0) } } @@ -237,9 +289,7 @@ pub struct AssetRegister { impl AssetRegister { fn new() -> Self { - AssetRegister { - assets: Vec::new(), - } + AssetRegister { assets: Vec::new() } } pub fn len(&self) -> usize { @@ -259,18 +309,20 @@ impl AssetRegister { } pub fn get_asset(&self, sudt_asset: SUDTAsset) -> Option<&Asset> { - match self.assets.iter().find(|(_, a)| a.as_slice()[..] == sudt_asset.as_slice()[..]) { + match self + .assets + .iter() + .find(|(_, a)| a.as_slice()[..] == sudt_asset.as_slice()[..]) + { Some((asset, _)) => Some(asset), None => None, } } pub fn guess_asset_from_script(&self, script: &Script) -> Option<&Asset> { - match self - .assets - .iter() - .find(|(_, sudt_asset)| sudt_asset.type_script().as_slice()[..] == script.as_slice()[..]) - { + match self.assets.iter().find(|(_, sudt_asset)| { + sudt_asset.type_script().as_slice()[..] == script.as_slice()[..] + }) { Some((asset, _)) => Some(asset), None => None, } diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/abort.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/abort.rs index c454be0..ffebd6a 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/abort.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/abort.rs @@ -9,7 +9,10 @@ use ckb_testtool::{ }; use perun_common::{perun_types::ChannelStatus, redeemer}; -use crate::perun::{self, harness, test::{cell::FundingCell, transaction::common::add_cap_to_a}}; +use crate::perun::{ + self, harness, + test::{cell::FundingCell, transaction::common::add_cap_to_a}, +}; use super::common::{channel_witness, create_cells}; diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/close.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/close.rs index e40f6f7..24767b8 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/close.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/close.rs @@ -14,7 +14,7 @@ use crate::perun::{ test::{cell::FundingCell, transaction::common::channel_witness}, }; -use super::common::{create_cells, add_cap_to_a}; +use super::common::{add_cap_to_a, create_cells}; #[derive(Debug, Clone)] pub struct CloseArgs { diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/common.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/common.rs index 3814aad..96ab1bf 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/common.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/common.rs @@ -1,10 +1,13 @@ use ckb_occupied_capacity::Capacity; use ckb_testtool::{ bytes, - ckb_types::{packed::{Byte32, CellOutput, OutPoint}, prelude::{Unpack, Pack}}, + ckb_types::{ + packed::{Byte32, CellOutput, OutPoint}, + prelude::{Pack, Unpack}, + }, context::Context, }; -use molecule::prelude::{Entity, Builder}; +use molecule::prelude::{Builder, Entity}; use perun_common::perun_types::Balances; use crate::perun; @@ -35,7 +38,15 @@ pub fn create_cells(ctx: &mut Context, hash: Byte32, outputs: Vec<(CellOutput, b pub fn add_cap_to_a(balances: &Balances, cap: Capacity) -> Balances { let bal_a: u64 = balances.ckbytes().nth0().unpack(); - balances.clone().as_builder().ckbytes( - balances.ckbytes().as_builder().nth0( - (cap.as_u64() + bal_a).pack()).build()).build() -} \ No newline at end of file + balances + .clone() + .as_builder() + .ckbytes( + balances + .ckbytes() + .as_builder() + .nth0((cap.as_u64() + bal_a).pack()) + .build(), + ) + .build() +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/force_close.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/force_close.rs index a767ab5..612ed7a 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/force_close.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/force_close.rs @@ -15,7 +15,7 @@ use crate::perun::{ test::{cell::FundingCell, transaction::common::channel_witness}, }; -use super::common::{create_cells, add_cap_to_a}; +use super::common::{add_cap_to_a, create_cells}; #[derive(Debug, Clone)] pub struct ForceCloseArgs { @@ -72,7 +72,7 @@ pub fn mk_force_close( // Rust... let channel_cap = env.min_capacity_for_channel(args.state.clone())?; - let balances = add_cap_to_a(&args.state.state().balances(), channel_cap); + let balances = add_cap_to_a(&args.state.state().balances(), channel_cap); // give ckbytes locked for channel cell to first party let f = |idx| env.build_lock_script(ctx, Bytes::from(vec![idx])); let outputs = balances.mk_outputs(f, vec![0, 1]); let outputs_data: Vec<_> = outputs.iter().map(|o| o.1.clone()).collect(); diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/fund.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/fund.rs index 15bd968..6300310 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/fund.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/fund.rs @@ -12,7 +12,10 @@ use perun_common::{fund, perun_types::ChannelStatus, redeemer}; use crate::perun::{ self, harness, - test::{cell::{FundingCell, mk_funding_cell}, FundingAgreement}, + test::{ + cell::{mk_funding_cell, FundingCell}, + FundingAgreement, + }, }; use super::common::{channel_witness, create_cells, create_funding_from}; @@ -66,14 +69,19 @@ pub fn mk_fund( let num_fund_ouputs = outputs.len(); let my_available_funds = Capacity::shannons(args.inputs.iter().map(|(_, c)| c.as_u64()).sum()); - let exchange_cell = create_funding_from(my_available_funds, (wanted + args.funding_agreement.sudt_max_cap_sum()).into_capacity())?; - let mut inputs = vec![ - CellInput::new_builder() - .previous_output(args.channel_cell) - .build(), - ]; + let exchange_cell = create_funding_from( + my_available_funds, + (wanted + args.funding_agreement.sudt_max_cap_sum()).into_capacity(), + )?; + let mut inputs = vec![CellInput::new_builder() + .previous_output(args.channel_cell) + .build()]; for (outpoint, _) in args.inputs.iter() { - inputs.push(CellInput::new_builder().previous_output(outpoint.clone()).build()); + inputs.push( + CellInput::new_builder() + .previous_output(outpoint.clone()) + .build(), + ); } // NOTE: mk_fund currently expects the be called for the last party funding the channel. // Otherwise the call to `mk_funded` returns a wrong channel state. @@ -111,12 +119,23 @@ pub fn mk_fund( .cell_deps(cell_deps) .header_deps(headers) .build(); - let tx = ctx.complete_tx(rtx); + let tx = ctx.complete_tx(rtx); create_cells(ctx, tx.hash(), outputs.clone()); Ok(FundResult { channel_cell: OutPoint::new(tx.hash(), num_fund_ouputs as u32), - funds_cells: outputs[..num_fund_ouputs].iter().enumerate().map(|(i, (co, bytes))| - mk_funding_cell(args.party_index, OutPoint::new(tx.hash(), i as u32), co, bytes.clone(), args.funding_agreement.register())).collect(), + funds_cells: outputs[..num_fund_ouputs] + .iter() + .enumerate() + .map(|(i, (co, bytes))| { + mk_funding_cell( + args.party_index, + OutPoint::new(tx.hash(), i as u32), + co, + bytes.clone(), + args.funding_agreement.register(), + ) + }) + .collect(), state: updated_cs, tx, }) diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/mod.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/mod.rs index b1d6673..1abcb5b 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/mod.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/mod.rs @@ -16,4 +16,25 @@ pub use force_close::*; mod dispute; pub use dispute::*; +mod vc_start; +pub use vc_start::*; + +pub mod vc_progress_no_update; +pub use vc_progress_no_update::*; + +pub mod vc_update_only; +pub use vc_update_only::*; + +pub mod vc_merge; +pub use vc_merge::*; + +pub mod vc_close1; +pub use vc_close1::*; + +pub mod vc_close2; +pub use vc_close2::*; + +pub mod vc_lc_update; +pub use vc_lc_update::*; + mod common; diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/open.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/open.rs index 808cd8e..232ad1c 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/open.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/open.rs @@ -14,7 +14,10 @@ use perun_common::perun_types::ChannelStatus; use crate::perun::{ self, harness, - test::{cell::{FundingCell, mk_funding_cell}, ChannelId, FundingAgreement}, + test::{ + cell::{mk_funding_cell, FundingCell}, + ChannelId, FundingAgreement, + }, }; use super::common::{create_cells, create_funding_from}; @@ -56,11 +59,9 @@ pub fn mk_open( env: &harness::Env, args: OpenArgs, ) -> Result { - let mut inputs = vec![ - CellInput::new_builder() - .previous_output(args.channel_token_outpoint) - .build(), - ]; + let mut inputs = vec![CellInput::new_builder() + .previous_output(args.channel_token_outpoint) + .build()]; for (outpoint, _) in args.inputs.iter() { inputs.push( CellInput::new_builder() @@ -79,7 +80,7 @@ pub fn mk_open( let wanted = args .funding_agreement .expected_ckbytes_funding_for(args.party_index)?; - + let pfls = |_| args.pfls_script.clone(); let balances = args.funding_agreement.mk_balances(vec![args.party_index])?; @@ -87,7 +88,10 @@ pub fn mk_open( let num_of_funds = outputs.len(); // TODO: Make sure enough funds available all cells! let my_available_funds = Capacity::shannons(args.inputs.iter().map(|(_, c)| c.as_u64()).sum()); - let exchange_cell_cap = create_funding_from(my_available_funds, (wanted + args.funding_agreement.sudt_max_cap_sum()).into_capacity())?; + let exchange_cell_cap = create_funding_from( + my_available_funds, + (wanted + args.funding_agreement.sudt_max_cap_sum()).into_capacity(), + )?; // NOTE: The ORDER here is important. We need to reference the outpoints later on by using the // correct index in the output array of the transaction we build. outputs.append( @@ -100,14 +104,15 @@ pub fn mk_open( .build(), Bytes::new(), ), - ].as_mut() + ] + .as_mut(), ); let outputs_data: Vec<_> = outputs.iter().map(|o| o.1.clone()).collect(); let cell_deps = vec![ env.always_success_script_dep.clone(), env.pcts_script_dep.clone(), - env.sample_udt_script_dep.clone(), // TODO: Make this generic! + env.sample_udt_script_dep.clone(), // TODO: Make this generic! ]; let rtx = TransactionBuilder::default() .inputs(inputs) @@ -120,8 +125,19 @@ pub fn mk_open( Ok(OpenResult { // See NOTE above for magic indices. channel_cell: OutPoint::new(tx.hash(), num_of_funds as u32), - funds_cells: outputs[..num_of_funds].iter().enumerate().map(|(i, (co, bytes))| - mk_funding_cell(args.party_index, OutPoint::new(tx.hash(), i as u32), co, bytes.clone(), args.funding_agreement.register())).collect(), + funds_cells: outputs[..num_of_funds] + .iter() + .enumerate() + .map(|(i, (co, bytes))| { + mk_funding_cell( + args.party_index, + OutPoint::new(tx.hash(), i as u32), + co, + bytes.clone(), + args.funding_agreement.register(), + ) + }) + .collect(), tx, pcts: args.pcts_script, state: initial_cs, diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close1.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close1.rs new file mode 100644 index 0000000..b21ce01 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close1.rs @@ -0,0 +1,121 @@ +use ckb_testtool::{ + ckb_types::packed::{CellInput, CellOutput, OutPoint, Script}, + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{perun_types::VirtualChannelStatus, redeemer}; + +use crate::perun::{ + self, harness, + test::transaction::common::channel_witness, + virtual_channel::{IdxMapDirection, IdxMapWithDirection}, +}; + +use super::{ + common::{add_cap_to_a, create_cells}, + ForceCloseArgs, +}; + +pub struct VCClose1Args { + pub parent_args: ForceCloseArgs, + pub vc_cell: OutPoint, + pub vc_status: VirtualChannelStatus, + pub idx_map_with_direction: IdxMapWithDirection, + pub vcts_script: Script, +} + +#[derive(Debug, Clone)] +pub struct VCClose1Result { + pub tx: TransactionView, + pub output_vc_cell: OutPoint, +} + +impl Default for VCClose1Result { + fn default() -> Self { + VCClose1Result { + tx: TransactionBuilder::default().build(), + output_vc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_close1( + ctx: &mut Context, + env: &harness::Env, + args: VCClose1Args, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + let mut inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + inputs.extend(args.parent_args.funds_cells.iter().cloned().map(|f| { + CellInput::new_builder() + .previous_output(f.outpoint()) + .build() + })); + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + let channel_cap = env.min_capacity_for_channel(args.parent_args.state.clone())?; + let balances = add_cap_to_a(&args.parent_args.state.state().balances(), channel_cap); // give ckbytes locked for channel cell to first party + let f = |idx| env.build_lock_script(ctx, Bytes::from(vec![idx])); + match args.idx_map_with_direction.direction { + IdxMapDirection::LedgerChannelToVirtualChannel => {} + _ => panic!("Invalid direction for idx_map"), + } + let mut outputs = balances.mk_unlocked_outputs( + f, + vec![0, 1], + &args.idx_map_with_direction.idx_map, + &args.vc_status.vcstate().balances(), + ); + let mut outputs_data: Vec<_> = outputs.iter().map(|o| o.1.clone()).collect(); + + let vcls_script = env.build_vcls(ctx, Default::default()); + let vc_status = args.vc_status.clone(); + let capacity_for_vc = env.min_capacity_for_vc_channel(vc_status.clone())?; + let vc_cell = CellOutput::new_builder() + .capacity(capacity_for_vc.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + outputs.push((vc_cell.clone(), vc_status.as_bytes())); + outputs_data.push(vc_status.as_bytes()); + let _output_vc_status = + VirtualChannelStatus::from_slice(&outputs_data[outputs.len() - 1]).unwrap(); + let force_close_action = redeemer!(ForceClose); + let witness_args = channel_witness!(force_close_action); + + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|o| o.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(args.parent_args.headers) + .witness(witness_args.as_bytes().pack()) + .cell_deps(cell_deps) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs.clone()); + Ok(VCClose1Result { + output_vc_cell: OutPoint::new(tx.hash(), (outputs.len() - 1) as u32), //vc cell is the last cell in the outputs + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close2.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close2.rs new file mode 100644 index 0000000..6b79729 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_close2.rs @@ -0,0 +1,114 @@ +use ckb_testtool::{ + ckb_types::packed::{CellInput, CellOutput, OutPoint, Script}, + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{perun_types::VirtualChannelStatus, redeemer}; + +use crate::perun::{ + self, harness, + test::transaction::common::channel_witness, + virtual_channel::{IdxMapDirection, IdxMapWithDirection}, +}; + +use super::{ + common::{add_cap_to_a, create_cells}, + ForceCloseArgs, +}; + +pub struct VCClose2Args { + pub parent_args: ForceCloseArgs, + pub vc_cell: OutPoint, + pub vc_status: VirtualChannelStatus, + pub idx_map_with_direction: IdxMapWithDirection, + pub vcts_script: Script, +} + +#[derive(Debug, Clone)] +pub struct VCClose2Result { + pub tx: TransactionView, +} + +impl Default for VCClose2Result { + fn default() -> Self { + VCClose2Result { + tx: TransactionBuilder::default().build(), + } + } +} + +pub fn mk_vc_close2( + ctx: &mut Context, + env: &harness::Env, + args: VCClose2Args, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + let mut inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + inputs.extend(args.parent_args.funds_cells.iter().cloned().map(|f| { + CellInput::new_builder() + .previous_output(f.outpoint()) + .build() + })); + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let vc_cell_cap = env.min_capacity_for_vc_channel(args.vc_status.clone())?; + let owner_idx: u8 = 0; + let onwer_vc_rent_payout = CellOutput::new_builder() + .capacity(vc_cell_cap.pack()) + .lock(env.build_lock_script(ctx, Bytes::from(vec![owner_idx]))) + .build(); + + let channel_cap = env.min_capacity_for_channel(args.parent_args.state.clone())?; + let balances = add_cap_to_a(&args.parent_args.state.state().balances(), channel_cap); // give ckbytes locked for channel cell to first party + let f = |idx| env.build_lock_script(ctx, Bytes::from(vec![idx])); + match args.idx_map_with_direction.direction { + IdxMapDirection::LedgerChannelToVirtualChannel => {} + _ => panic!("Invalid direction for idx_map"), + } + + let mut outputs = balances.mk_unlocked_outputs( + f, + vec![0, 1], + &args.idx_map_with_direction.idx_map, + &args.vc_status.vcstate().balances(), + ); + outputs.push((onwer_vc_rent_payout, Bytes::new())); + let outputs_data: Vec<_> = outputs.iter().map(|o| o.1.clone()).collect(); + + let force_close_action = redeemer!(ForceClose); + let witness_args = channel_witness!(force_close_action); + + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|o| o.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(args.parent_args.headers) + .witness(witness_args.as_bytes().pack()) + .cell_deps(cell_deps) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(VCClose2Result { tx }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_lc_update.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_lc_update.rs new file mode 100644 index 0000000..a293f9e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_lc_update.rs @@ -0,0 +1,131 @@ +// use std::cell::Cell; + +use crate::perun::{self, harness, test::transaction::common::channel_witness}; +use ckb_testtool::{ + ckb_types::{ + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{dispute, perun_types::VirtualChannelStatus, redeemer}; + +use super::{common::create_cells, DisputeArgs}; + +pub struct VCLCUpdateArgs { + pub parent_args: DisputeArgs, + pub vc_cell: OutPoint, + pub vc_status: VirtualChannelStatus, + pub sigs: [Vec; 2], + pub vcts_script: Script, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct VCLCUpdateResult { + pub tx: TransactionView, + pub parent_cell: OutPoint, + pub vc_cell: OutPoint, +} + +impl Default for VCLCUpdateResult { + fn default() -> Self { + VCLCUpdateResult { + tx: TransactionBuilder::default().build(), + parent_cell: OutPoint::default(), + vc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_lc_update( + ctx: &mut Context, + env: &harness::Env, + args: VCLCUpdateArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + //add inputs to tx + //1. parent lc cell, 2. vc cell, 3. payment input + let inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let pcls_script = env.build_pcls(ctx, Default::default()); + let vcls_script = env.build_vcls(ctx, Default::default()); + let capacity_for_cs = env.min_capacity_for_channel(args.parent_args.state.clone())?; + // create cells for outputs + let parent_channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(pcls_script.clone()) + .type_(Some(args.parent_args.pcts_script.clone()).pack()) + .build(); + let vc_status = args.vc_status.clone(); + let capacity_for_vc = env.min_capacity_for_vc_channel(vc_status.clone())?; + let vc_cell = CellOutput::new_builder() + .capacity(capacity_for_vc.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + + // add cells to outputs + // 1. parent lc cell 2. vc cell + let outputs = vec![ + ( + parent_channel_cell.clone(), + args.parent_args.state.as_bytes(), + ), + (vc_cell.clone(), args.vc_status.as_bytes()), + ]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + // add witness args + let lc_dispute_action = channel_witness!(redeemer!(dispute!( + args.parent_args.sigs[0].pack(), + args.parent_args.sigs[1].pack() + ))); + let vc_dispute_action = channel_witness!(redeemer!(dispute!( + args.sigs[0].pack(), + args.sigs[1].pack() + ))); + let witness_vec = vec![ + (lc_dispute_action.clone(), lc_dispute_action.as_bytes()), + (vc_dispute_action.clone(), vc_dispute_action.as_bytes()), + ]; + let witness_args: Vec<_> = witness_vec.iter().map(|e| e.1.clone()).collect(); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|e| e.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(headers) + .witnesses(witness_args.pack()) + .cell_deps(cell_deps) + .build(); + + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(VCLCUpdateResult { + parent_cell: OutPoint::new(tx.hash(), 0), + vc_cell: OutPoint::new(tx.hash(), 1), + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_merge.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_merge.rs new file mode 100644 index 0000000..cee880b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_merge.rs @@ -0,0 +1,101 @@ +use crate::perun::{self, harness}; +use ckb_testtool::{ + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::perun_types::VirtualChannelStatus; + +use super::common::create_cells; + +pub struct VCMergeArgs { + pub vc_cell1: OutPoint, + pub vc_cell2: OutPoint, + pub party_index: u8, + pub vc_status1: VirtualChannelStatus, + pub vc_status2: VirtualChannelStatus, + pub vcts_script: Script, +} + +#[derive(Debug, Clone)] +pub struct VCMergeResult { + pub tx: TransactionView, + pub final_vc_cell: OutPoint, +} + +impl Default for VCMergeResult { + fn default() -> Self { + VCMergeResult { + tx: TransactionBuilder::default().build(), + final_vc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_merge( + ctx: &mut Context, + env: &harness::Env, + args: VCMergeArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.party_index); + + let inputs = vec![ + CellInput::new_builder() + .previous_output(args.vc_cell1) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell2) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let vcls_script = env.build_vcls(ctx, Default::default()); + let vc_status2 = args.vc_status2.clone(); + let capacity_for_vc2 = env.min_capacity_for_vc_channel(vc_status2.clone())?; + let vc_cell2 = CellOutput::new_builder() + .capacity(capacity_for_vc2.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + let owner_idx: u8 = 0; + let onwer_vc_rent_payout = CellOutput::new_builder() + .capacity(capacity_for_vc2.pack()) + .lock(env.build_lock_script(ctx, Bytes::from(vec![owner_idx]))) + .build(); + let outputs = vec![ + (vc_cell2.clone(), vc_status2.as_bytes()), + (onwer_vc_rent_payout, Bytes::new()), + ]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|e| e.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(headers) + .cell_deps(cell_deps) + .build(); + + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + + Ok(VCMergeResult { + final_vc_cell: OutPoint::new(tx.hash(), 0), + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_progress_no_update.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_progress_no_update.rs new file mode 100644 index 0000000..d35a7a4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_progress_no_update.rs @@ -0,0 +1,120 @@ +use crate::perun::{self, harness, test::transaction::common::channel_witness}; +use ckb_testtool::{ + ckb_types::{ + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{dispute, perun_types::VirtualChannelStatus, redeemer}; + +use super::{common::create_cells, DisputeArgs}; + +pub struct VCProgressNoUpdateArgs { + pub parent_args: DisputeArgs, + pub vc_cell: OutPoint, + pub vc_status: VirtualChannelStatus, + pub vcts_script: Script, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct VCProgressNoUpdateResult { + pub tx: TransactionView, + pub parent_cell: OutPoint, + pub vc_cell: OutPoint, +} + +impl Default for VCProgressNoUpdateResult { + fn default() -> Self { + VCProgressNoUpdateResult { + tx: TransactionBuilder::default().build(), + parent_cell: OutPoint::default(), + vc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_progress_no_update( + ctx: &mut Context, + env: &harness::Env, + args: VCProgressNoUpdateArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + //add inputs to tx + //1. parent lc cell, 2. vc cell, 3. payment input + let inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let pcls_script = env.build_pcls(ctx, Default::default()); + let vcls_script = env.build_vcls(ctx, Default::default()); + let capacity_for_cs = env.min_capacity_for_channel(args.parent_args.state.clone())?; + // create cells for outputs + let parent_channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(pcls_script.clone()) + .type_(Some(args.parent_args.pcts_script.clone()).pack()) + .build(); + let vc_status = args.vc_status.clone(); + let capacity_for_vc = env.min_capacity_for_vc_channel(vc_status.clone())?; + let vc_cell = CellOutput::new_builder() + .capacity(capacity_for_vc.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + + // add cells to outputs + // 1. parent lc cell 2. vc cell + let outputs = vec![ + ( + parent_channel_cell.clone(), + args.parent_args.state.as_bytes(), + ), + (vc_cell.clone(), args.vc_status.as_bytes()), + ]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + // add witness args + let dispute_action = redeemer!(dispute!( + args.parent_args.sigs[0].pack(), + args.parent_args.sigs[1].pack() + )); + let witness_args = channel_witness!(dispute_action); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|e| e.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(headers) + .witness(witness_args.as_bytes().pack()) + .cell_deps(cell_deps) + .build(); + + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(VCProgressNoUpdateResult { + parent_cell: OutPoint::new(tx.hash(), 0), + vc_cell: OutPoint::new(tx.hash(), 1), + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_start.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_start.rs new file mode 100644 index 0000000..1fecf9e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_start.rs @@ -0,0 +1,128 @@ +use ckb_testtool::{ + ckb_types::{ + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{perun_types::VirtualChannelStatus, redeemer, vc_dispute}; + +use crate::perun::{self, harness, test::transaction::common::channel_witness}; + +use super::{common::create_cells, DisputeArgs}; + +#[derive(Debug, Clone)] +pub struct VCStartArgs { + /// Parent Cell dispute args + pub parent_args: DisputeArgs, + + pub vc_status: VirtualChannelStatus, + /// The DER encoded signatures for the virtual channel state in proper order of parties. + pub sigs: [Vec; 2], + /// The Perun virtual channel type script used for the current channel. + pub vcts_script: Script, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct VCStartResult { + pub tx: TransactionView, + pub vc_cell: OutPoint, + pub parent_lc_cell: OutPoint, +} + +impl Default for VCStartResult { + fn default() -> Self { + VCStartResult { + tx: TransactionBuilder::default().build(), + vc_cell: OutPoint::default(), + parent_lc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_start( + ctx: &mut Context, + env: &harness::Env, + args: VCStartArgs, +) -> Result { + //input cell for gas fees + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + + // add inputs to tx + // first parent lc cell and then payment input + let inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let pcls_script = env.build_pcls(ctx, Default::default()); + let vcls_script = env.build_vcls(ctx, Default::default()); + let capacity_for_cs = env.min_capacity_for_channel(args.parent_args.state.clone())?; + let parent_channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(pcls_script.clone()) + .type_(Some(args.parent_args.pcts_script.clone()).pack()) + .build(); + + // create vc cell for outputs + let initial_vc = args.vc_status.clone(); + let capacity_for_vc = env.min_capacity_for_vc_channel(initial_vc.clone())?; + let vc_cell = CellOutput::new_builder() + .capacity(capacity_for_vc.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + + // add cells to outputs + //first lc cell and then vc cell + let outputs = vec![ + ( + parent_channel_cell.clone(), + args.parent_args.state.as_bytes(), + ), + (vc_cell.clone(), args.vc_status.as_bytes()), + ]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + // add witness args + let dispute_action = redeemer!(vc_dispute!( + args.sigs[0].pack(), + args.sigs[1].pack(), + args.parent_args.sigs[0].pack(), + args.parent_args.sigs[1].pack() + )); + let witness_args = channel_witness!(dispute_action); + + // witnesses.push(witness_args.as_bytes()); + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|e| e.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(headers) + .witness(witness_args.as_bytes().pack()) + .cell_deps(cell_deps) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(VCStartResult { + parent_lc_cell: OutPoint::new(tx.hash(), 0), + vc_cell: OutPoint::new(tx.hash(), 1), + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_update_only.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_update_only.rs new file mode 100644 index 0000000..d34c61c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/vc_update_only.rs @@ -0,0 +1,130 @@ +use ckb_testtool::{ + ckb_types::{ + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; + +use crate::perun::{self, harness, test::transaction::common::channel_witness}; +use perun_common::{dispute, perun_types::VirtualChannelStatus, redeemer}; + +use super::{common::create_cells, DisputeArgs}; + +pub struct VCUpdateOnlyArgs { + pub parent_args: DisputeArgs, + pub vc_cell: OutPoint, + pub vc_status: VirtualChannelStatus, + pub sigs: [Vec; 2], + pub vcts_script: Script, + pub party_index: u8, +} + +pub struct VCUpdateOnlyResult { + pub tx: TransactionView, + pub parent_cell: OutPoint, + pub vc_cell: OutPoint, +} + +impl Default for VCUpdateOnlyResult { + fn default() -> Self { + VCUpdateOnlyResult { + tx: TransactionBuilder::default().build(), + parent_cell: OutPoint::default(), + vc_cell: OutPoint::default(), + } + } +} + +pub fn mk_vc_update_only( + ctx: &mut Context, + env: &harness::Env, + args: VCUpdateOnlyArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.parent_args.party_index); + //add inputs to tx + //1. parent lc cell, 2. vc cell, 3. payment input + let inputs = vec![ + CellInput::new_builder() + .previous_output(args.parent_args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(args.vc_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.pfls_script_dep.clone(), + env.always_success_script_dep.clone(), + env.vcts_script_dep.clone(), + env.vcls_script_dep.clone(), + ]; + + let pcls_script = env.build_pcls(ctx, Default::default()); + let vcls_script = env.build_vcls(ctx, Default::default()); + let capacity_for_cs = env.min_capacity_for_channel(args.parent_args.state.clone())?; + + // create cells for outputs + let parent_channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(pcls_script.clone()) + .type_(Some(args.parent_args.pcts_script.clone()).pack()) + .build(); + let vc_status = args.vc_status.clone(); + let capacity_for_vc = env.min_capacity_for_vc_channel(vc_status.clone())?; + let vc_cell = CellOutput::new_builder() + .capacity(capacity_for_vc.pack()) + .lock(vcls_script.clone()) + .type_(Some(args.vcts_script.clone()).pack()) + .build(); + + // add cells to outputs + // 1. parent lc cell 2. vc cell + let outputs = vec![ + ( + parent_channel_cell.clone(), + args.parent_args.state.as_bytes(), + ), + (vc_cell.clone(), args.vc_status.as_bytes()), + ]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + // add witness args + let lc_dispute_action = channel_witness!(redeemer!(dispute!( + args.parent_args.sigs[0].pack(), + args.parent_args.sigs[1].pack() + ))); + let vc_dispute_action = channel_witness!(redeemer!(dispute!( + args.sigs[0].pack(), + args.sigs[1].pack() + ))); + let witness_vec = vec![ + (lc_dispute_action.clone(), lc_dispute_action.as_bytes()), + (vc_dispute_action.clone(), vc_dispute_action.as_bytes()), + ]; + let witness_args: Vec<_> = witness_vec.iter().map(|e| e.1.clone()).collect(); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|e| e.0.clone())) + .outputs_data(outputs_data.pack()) + .header_deps(headers) + .witnesses(witness_args.pack()) + .cell_deps(cell_deps) + .build(); + + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(VCUpdateOnlyResult { + parent_cell: OutPoint::new(tx.hash(), 0), + vc_cell: OutPoint::new(tx.hash(), 1), + tx, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/virtual_channel.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/virtual_channel.rs new file mode 100644 index 0000000..3dd7007 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/virtual_channel.rs @@ -0,0 +1,329 @@ +use ckb_testtool::{ + ckb_types::{ + packed::{OutPoint, Script}, + prelude::{Builder, Entity, Pack, Unpack}, + }, + context::Context, +}; +use k256::ecdsa::VerifyingKey; +use perun_common::{ + cfalse, ctrue, + helpers::blake2b256, + perun_types::{ + ChannelParametersBuilder, ChannelState, IndexMapBuilder, ParentDataBuilder, + ParentsVecBuilder, Participant, SUDTAllocation, VCChannelConstants, + VCChannelConstantsBuilder, VirtualChannelStatus, + }, +}; + +use super::test::FundingAgreement; +use super::Account; +use crate::perun::{ + self, + test::{keys, ChannelId, Client}, +}; +use crate::perun::{channel::Channel, test}; +use std::collections::HashMap; +use std::fmt::Debug; + +#[derive(Debug, Clone)] +pub struct VirtualChannel { + // acitve_part: test::Client + vc_status: VirtualChannelStatus, + id: ChannelId, + vcts: Script, + vcls: Script, + /// All available parties. + parts: HashMap, + idx_map: VCIndexMap, + + /// vc cell + cell: OutPoint, +} + +#[derive(Debug, Clone)] +pub enum IdxMapDirection { + LedgerChannelToVirtualChannel, + VirtualChannelToLedgerChannel, +} + +#[derive(Debug, Clone)] +pub struct IdxMapWithDirection { + pub idx_map: [u8; 2], + pub direction: IdxMapDirection, +} +#[derive(Debug, Clone)] +pub struct VCIndexMap { + pub parent1: [u8; 2], + pub parent2: [u8; 2], +} + +impl VCIndexMap { + pub fn invert_map(&self, parent: usize) -> [u8; 2] { + let parent_map = self.get(parent).expect("no parent").clone(); + let mut inverted = [0u8; 2]; + inverted[parent_map[0 as usize] as usize] = 0; + inverted[parent_map[1 as usize] as usize] = 1; + inverted + } + + pub fn get(&self, parent: usize) -> Option<&[u8; 2]> { + match parent { + 0 => Some(&self.parent1), + 1 => Some(&self.parent2), + _ => None, + } + } +} + +impl VirtualChannel { + pub fn new( + context: &mut Context, + env: &perun::harness::Env, + parts: &[perun::TestAccount], + funding_agreement: &FundingAgreement, + chan_ai: &Channel, + chan_bi: &Channel, + idx_map: &VCIndexMap, + nonce: &[u8; 32], + owner: &Participant, + ) -> Self { + let m_parts: HashMap<_, _> = parts + .iter() + .enumerate() + .map(|(i, p)| { + ( + p.name().clone(), + perun::test::Client::new(i as u8, p.name(), p.sk.clone()), + ) + }) + .collect(); + let parties_vc = + funding_agreement.mk_participants(context, &env, env.min_capacity_no_script); + let vc_chan_params = ChannelParametersBuilder::default() + .party_a(parties_vc[0].clone()) + .party_b(parties_vc[1].clone()) + .nonce(nonce.clone().pack()) + .challenge_duration(env.challenge_duration.pack()) + .app(Default::default()) + .is_ledger_channel(cfalse!()) + .is_virtual_channel(ctrue!()) + .build(); + let cid_raw = blake2b256(vc_chan_params.as_slice()); + let cid = ChannelId::from(cid_raw); + + let parents_builder = ParentsVecBuilder::default(); + let parent1 = ParentDataBuilder::default() + .pcts_hash(chan_ai.pcts().calc_script_hash()) + .idx_map( + IndexMapBuilder::default() + .nth0(idx_map.parent1[0].clone().into()) + .nth1(idx_map.parent1[1].clone().into()) + .build(), + ) + .build(); + let parent2 = ParentDataBuilder::default() + .pcts_hash(chan_bi.pcts().calc_script_hash()) + .idx_map( + IndexMapBuilder::default() + .nth0(idx_map.parent2[0].clone().into()) + .nth1(idx_map.parent2[1].clone().into()) + .build(), + ) + .build(); + let parents = parents_builder.push(parent1).push(parent2).build(); + let first_force_close = false; + // Build VirtualChannelStatus + let vc_status = match env.build_virtual_channel_state( + &cid, + &funding_agreement, + &parents, + first_force_close, + owner.clone(), + ) { + Ok(vc_status) => vc_status, + Err(e) => panic!("Error building virtual channel state: {}", e), + }; + + let vc_channel_constants = VCChannelConstantsBuilder::default() + .params(vc_chan_params.clone()) + .vcls_code_hash(env.get_vcls_().calc_script_hash()) + .vcls_hash_type(env.get_vcls_().hash_type().clone()) + .build(); + let vcts = env.build_vcts(context, vc_channel_constants.as_bytes()); + + VirtualChannel { + vc_status: vc_status, + vcts: vcts, + id: cid, + vcls: env.get_vcls_().clone(), + parts: m_parts, + idx_map: idx_map.clone(), + cell: OutPoint::default(), + } + } + + pub fn vc_status(&self) -> &VirtualChannelStatus { + &self.vc_status + } + + pub fn vcts(&self) -> &Script { + &self.vcts + } + + pub fn vcls(&self) -> &Script { + &self.vcls + } + + pub fn id(&self) -> &ChannelId { + &self.id + } + + pub fn cell(&self) -> &OutPoint { + &self.cell + } + pub fn set_cell(&mut self, cell: OutPoint) { + self.cell = cell; + } + + pub fn update( + &mut self, + update: impl Fn(&ChannelState) -> Result, + ) -> &mut Self { + let new_state = update(&self.vc_status.vcstate()).expect("update failed"); + self.vc_status = self + .vc_status + .clone() + .as_builder() + .vcstate(new_state) + .build(); + self + } + + pub fn sigs_for_vc_status(&self) -> Result<[Vec; 2], perun::Error> { + // We have to unpack the ChannelConstants like this. Otherwise the molecule header is still + // part of the slice. On-chain we have no problem due to unpacking the arguments, but this + // does not seem possible in this scope. + let bytes = self.vcts.args().raw_data(); + // We want to have the correct order of clients in an array to construct signatures. For + // consistency we use the ChannelConstants which are also used to construct the channel and + // look up the participants according to their public key identifier. + let s = VCChannelConstants::from_slice(&bytes)?; + let resolve_client = |verifying_key_raw: Vec| -> Result { + let verifying_key = VerifyingKey::from_sec1_bytes(verifying_key_raw.as_slice())?; + let pubkey = keys::verifying_key_to_byte_array(&verifying_key); + self.parts + .values() + .cloned() + .find(|c| c.pubkey() == pubkey) + .ok_or("unknown participant in channel parameters".into()) + }; + let clients: Result, _> = s + .params() + .mk_party_pubkeys() + .iter() + .cloned() + .map(resolve_client) + .collect(); + let sigs: Result, _> = clients? + .iter() + .map(|p| p.sign(self.vc_status.vcstate())) + .collect(); + let sig_arr: [Vec; 2] = sigs?.try_into()?; + Ok(sig_arr) + } +} + +pub fn update_virtual_channel<'a>( + fa: &'a FundingAgreement, + vc_id: ChannelId, + vc_to_lc_idx_map: &'a [u8; 2], +) -> impl Fn(&ChannelState) -> Result + 'a { + move |s| { + // create a function for current balances of a lc, which takes another funding agreement with its locked + let locked = fa.mk_locked_balances(vc_id)?; + let vc_alloc = locked.get(0).expect("no 0th in SubAlloc: no funds locked"); + // instead of creating locked balances, directly create balances and pass it to the new state. + let locked_ckb_1 = vc_alloc.balances().ckbytes().get(0).expect("no ckbytes"); + let locked_ckb_2 = vc_alloc.balances().ckbytes().get(1).expect("no ckbytes"); + + // let bals = s.clone().balances(); + let old_ckb_1 = s + .balances() + .ckbytes() + .clone() + .get(vc_to_lc_idx_map[0].into()) + .expect("no ckbytes"); + let updated_ckb = old_ckb_1 - locked_ckb_1; + + let old_ckb_2 = s + .balances() + .ckbytes() + .clone() + .get(vc_to_lc_idx_map[1].into()) + .expect("no ckbytes"); + let updated_ckb_2 = old_ckb_2 - locked_ckb_2; + + let updated_ckb_dist = s + .balances() + .ckbytes() + .clone() + .as_builder() + .nth0(updated_ckb.pack()) + .nth1(updated_ckb_2.pack()) + .build(); + + let mut sudt_allocation_builder = SUDTAllocation::new_builder(); + + for (_, vc_sudt_bals) in vc_alloc.balances().sudts().clone().into_iter().enumerate() { + for (_, lc_sudt_bals) in s.balances().sudts().clone().into_iter().enumerate() { + if vc_sudt_bals.asset().type_script().as_slice() + == lc_sudt_bals.asset().type_script().as_slice() + { + let locked_sudt_bals1 = vc_sudt_bals.distribution().get(0).expect("no 0th"); + let locked_sudt_bals2 = vc_sudt_bals.distribution().get(1).expect("no 1st"); + + let old_sudt_bals1 = lc_sudt_bals + .distribution() + .get(vc_to_lc_idx_map[0].into()) + .expect("no 0th"); + let old_sudt_bals2 = lc_sudt_bals + .distribution() + .get(vc_to_lc_idx_map[1].into()) + .expect("no 1st"); + + let udpated_sudt_bals1 = old_sudt_bals1 - locked_sudt_bals1; + let udpated_sudt_bals2 = old_sudt_bals2 - locked_sudt_bals2; + + let updated_sudt_dist = lc_sudt_bals + .distribution() + .clone() + .as_builder() + .nth0(udpated_sudt_bals1.pack()) + .nth1(udpated_sudt_bals2.pack()) + .build(); + let updated_sudt_bals = lc_sudt_bals + .clone() + .as_builder() + .distribution(updated_sudt_dist) + .build(); + sudt_allocation_builder = sudt_allocation_builder.push(updated_sudt_bals); + } + } + } + let sudt_alloc = sudt_allocation_builder.build(); + Ok(s.clone() + .as_builder() + .version((Unpack::::unpack(&s.version()) + 1u64).pack()) + .balances( + s.balances() + .clone() + .as_builder() + .ckbytes(updated_ckb_dist) + .sudts(sudt_alloc) + .locked(locked) + .build(), + ) + .build()) + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/tests.rs b/payment-channel-ckb/devnet/contracts/tests/src/tests.rs index f21be32..4b26755 100644 --- a/payment-channel-ckb/devnet/contracts/tests/src/tests.rs +++ b/payment-channel-ckb/devnet/contracts/tests/src/tests.rs @@ -1,31 +1,40 @@ use crate::perun::mutators::*; use crate::perun::random; +use crate::perun::virtual_channel::*; use super::*; use ckb_occupied_capacity::Capacity; use ckb_testtool::ckb_types::{bytes::Bytes, packed::*, prelude::*}; use ckb_testtool::context::Context; use perun; -use perun::test; +use perun::{test, virtual_channel}; use perun_common::helpers::blake2b256; -use perun_common::perun_types::{Balances, Bool, ChannelState, SEC1EncodedPubKey, CKByteDistribution}; -use perun_common::sig::verify_signature; +use perun_common::perun_types::{ + Balances, Bool, CKByteDistribution, ChannelState, LockedBalances, SEC1EncodedPubKey, SubAlloc, +}; +use perun_common::sig::{ethereum_message_hash, verify_signature}; +use std::cell::RefCell; +use std::rc::Rc; +use std::sync::Mutex; -const MAX_CYCLES: u64 = 10 * 10_000_000; +const MAX_CYCLES: u64 = 100 * 10_000_000; const CHALLENGE_DURATION_MS: u64 = 10 * 1000; +// Include your tests here +// See https://github.com/xxuejie/ckb-native-build-sample/blob/main/tests/src/tests.rs for more examples + #[test] fn test_signature() { // This tests the interoperability between the on-chain signature verification // and the key generation & signing in the perun-ckb-backend's wallet. // This signature was generated by the wallet in the perun-ckb-backend - let sig_string = "3045022100a4f8768be2e5afdcbcfee600eb963caf1957d32edca49390e6f5a4933c2f6dcd02207fd9d2b5928266e9aeee039285508da1dbdbeec67cb995fd8735e1795bf53e5f"; + let sig_string = "3044022066c65aeea05cb28cc851712e6843ea8aa1bb6b8beca2682c78842a0d78da7716022039da4917d7bdb83c84f82b6dc2d8e91ff935b13766bd0e44239d3a1f0ae195f5"; let sig = hex::decode(sig_string).expect("decoding signature"); let sig_bytes: Bytes = sig.into(); // This public key was generated by the wallet in the perun-ckb-backend - let pubkey_string = "02d1ab4e7cbfb2262de6f3f816d9b044970162a6a2ae0e6b0ff9b082e315c5e152"; + let pubkey_string = "022eddb5384f532a60658f6bc392d487b38813b8ae170e365fcbc34d8f869b2e9c"; let pubkey = hex::decode(pubkey_string).expect("decoding pubkey"); let pubkey_bytes: [Byte; 33] = pubkey .iter() @@ -36,7 +45,18 @@ fn test_signature() { SEC1EncodedPubKey::new_builder().set(pubkey_bytes).build(); let balances_array: [Uint64; 2] = [10u64.pack(), 11u64.pack()]; - let balances = Balances::new_builder().ckbytes(CKByteDistribution::new_builder().set(balances_array).build()).build(); + let balances = Balances::new_builder() + .ckbytes( + CKByteDistribution::new_builder() + .set(balances_array) + .build(), + ) + .locked( + LockedBalances::new_builder() + .push(SubAlloc::new_builder().build()) + .build(), + ) + .build(); let channel_state = ChannelState::new_builder() .channel_id(Byte32::zero()) .balances(balances) @@ -44,13 +64,12 @@ fn test_signature() { .version(10u64.pack()) .build(); let msg = channel_state.as_slice(); - let msg_hash = blake2b256(msg); - + let msg_hash = ethereum_message_hash(msg); verify_signature(&msg_hash, &sig_bytes, pubkey.as_slice()).expect("valid signature"); } -// TODO: Add mutator to channel state that can be passed to dispute, and close. #[test] +// TODO: Add mutator to channel state that can be passed to dispute, and close. fn channel_test_bench() -> Result<(), perun::Error> { let res = [ test_funding_abort, @@ -68,17 +87,43 @@ fn channel_test_bench() -> Result<(), perun::Error> { ] .iter() .map(|test| { - let mut context = Context::default(); - let pe = perun::harness::Env::new(&mut context, MAX_CYCLES, CHALLENGE_DURATION_MS) + let mut context = Rc::new(Mutex::new(RefCell::new(Context::default()))); + let pe = perun::harness::Env::new(context.clone(), MAX_CYCLES, CHALLENGE_DURATION_MS) .expect("preparing environment"); - test(&mut context, &pe) + test(context, &pe) + }) + .collect::>(); + res.into_iter().collect() +} + +#[test] +fn channel_vc_test_bench() -> Result<(), perun::Error> { + let res = [ + test_vc_start, + test_vc_progress_no_update, + test_vc_progress_update1, + test_vc_progress_update2, + test_vc_merge, + test_vc_close1, + test_vc_close2, + test_vc_happy, + test_vc_happy_multi_asset, + test_vc_happy_with_merge, + test_vc_happy_multi_asset_with_merge, + ] + .iter() + .map(|test| { + let context = Rc::new(Mutex::new(RefCell::new(Context::default()))); + let pe = perun::harness::Env::new(context.clone(), MAX_CYCLES, CHALLENGE_DURATION_MS) + .expect("preparing environment"); + test(context, &pe) }) .collect::>(); res.into_iter().collect() } fn create_channel_test( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, parts: &[perun::TestAccount], test: impl Fn(&mut perun::channel::Channel) -> Result<(), perun::Error>, @@ -87,8 +132,26 @@ fn create_channel_test( test(&mut chan) } +fn create_vc_channel_test( + context: Rc>>, + env: &perun::harness::Env, + parts_ai: &[perun::TestAccount], + parts_bi: &[perun::TestAccount], + test: impl Fn( + &mut perun::channel::Channel, + &mut perun::channel::Channel, + ) -> Result<(), perun::Error>, +) -> Result<(), perun::Error> { + // Create channels + let mut chan_ai = perun::channel::Channel::new(context.clone(), env, parts_ai); + let mut chan_bi = perun::channel::Channel::new(context.clone(), env, parts_bi); + + // Run the test function with mutable references + test(&mut chan_ai, &mut chan_bi) +} + fn test_funding_abort( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -116,7 +179,7 @@ fn test_funding_abort( } fn test_successful_funding_without_udt( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -142,9 +205,8 @@ fn test_successful_funding_without_udt( }) } - fn test_successful_funding_with_udt( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -153,15 +215,16 @@ fn test_successful_funding_with_udt( Capacity::bytes(100)?.as_u64(), Capacity::bytes(100)?.as_u64(), ]; - let asset_funding = [ - 20u128, - 30u128, - ]; + let asset_funding = [20u128, 30u128]; let funding_agreement = test::FundingAgreement::new_with_capacities_and_sudt( parts.iter().cloned().zip(funding.iter().cloned()).collect(), &env.sample_udt_script, env.sample_udt_max_cap.as_u64(), - parts.iter().cloned().zip(asset_funding.iter().cloned()).collect(), + parts + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), ); create_channel_test(context, env, &parts, |chan| { chan.with(alice) @@ -177,7 +240,10 @@ fn test_successful_funding_with_udt( }) } -fn test_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { +fn test_close( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); let parts = [random::account(alice), random::account(bob)]; let funding = [ @@ -206,7 +272,10 @@ fn test_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), pe }) } -fn test_force_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { +fn test_force_close( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); let parts = [random::account(alice), random::account(bob)]; let funding = [ @@ -236,7 +305,10 @@ fn test_force_close(context: &mut Context, env: &perun::harness::Env) -> Result< }) } -fn test_early_force_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { +fn test_early_force_close( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); let parts = [random::account(alice), random::account(bob)]; let funding = [ @@ -257,7 +329,10 @@ fn test_early_force_close(context: &mut Context, env: &perun::harness::Env) -> R chan.with(bob).dispute().expect("invalid channel dispute"); - chan.with(bob).invalid().force_close().expect("force closing channel"); + chan.with(bob) + .invalid() + .force_close() + .expect("force closing channel"); chan.assert(); Ok(()) @@ -265,7 +340,7 @@ fn test_early_force_close(context: &mut Context, env: &perun::harness::Env) -> R } fn test_multiple_disputes_same_version( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -302,7 +377,7 @@ fn test_multiple_disputes_same_version( } fn test_multiple_disputes( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -340,7 +415,7 @@ fn test_multiple_disputes( } fn test_multi_asset_payment( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -349,15 +424,16 @@ fn test_multi_asset_payment( Capacity::bytes(100)?.as_u64(), Capacity::bytes(100)?.as_u64(), ]; - let asset_funding = [ - 20u128, - 30u128, - ]; + let asset_funding = [20u128, 30u128]; let funding_agreement = test::FundingAgreement::new_with_capacities_and_sudt( parts.iter().cloned().zip(funding.iter().cloned()).collect(), &env.sample_udt_script, env.sample_udt_max_cap.as_u64(), - parts.iter().cloned().zip(asset_funding.iter().cloned()).collect(), + parts + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), ); create_channel_test(context, env, &parts, |chan| { chan.with(alice) @@ -371,7 +447,10 @@ fn test_multi_asset_payment( chan.update(pay_ckbytes(Direction::AtoB, 50)); chan.update(pay_sudt(Direction::BtoA, 10, 0)); - chan.with(alice).finalize().close().expect("closing channel"); + chan.with(alice) + .finalize() + .close() + .expect("closing channel"); chan.assert(); Ok(()) @@ -379,24 +458,22 @@ fn test_multi_asset_payment( } pub fn test_multi_asset_abort( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); let parts = [random::account(alice), random::account(bob)]; - let funding = [ - Capacity::bytes(0)?.as_u64(), - Capacity::bytes(0)?.as_u64(), - ]; - let asset_funding = [ - 30u128, - 20u128, - ]; + let funding = [Capacity::bytes(0)?.as_u64(), Capacity::bytes(0)?.as_u64()]; + let asset_funding = [30u128, 20u128]; let funding_agreement = test::FundingAgreement::new_with_capacities_and_sudt( parts.iter().cloned().zip(funding.iter().cloned()).collect(), &env.sample_udt_script, env.sample_udt_max_cap.as_u64(), - parts.iter().cloned().zip(asset_funding.iter().cloned()).collect(), + parts + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), ); create_channel_test(context, env, &parts, |chan| { chan.with(alice) @@ -411,24 +488,22 @@ pub fn test_multi_asset_abort( } pub fn test_multi_asset_abort_zero_sudt_balance( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); let parts = [random::account(alice), random::account(bob)]; - let funding = [ - Capacity::bytes(0)?.as_u64(), - Capacity::bytes(0)?.as_u64(), - ]; - let asset_funding = [ - 0u128, - 0u128, - ]; + let funding = [Capacity::bytes(0)?.as_u64(), Capacity::bytes(0)?.as_u64()]; + let asset_funding = [0u128, 0u128]; let funding_agreement = test::FundingAgreement::new_with_capacities_and_sudt( parts.iter().cloned().zip(funding.iter().cloned()).collect(), &env.sample_udt_script, env.sample_udt_max_cap.as_u64(), - parts.iter().cloned().zip(asset_funding.iter().cloned()).collect(), + parts + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), ); create_channel_test(context, env, &parts, |chan| { chan.with(alice) @@ -443,7 +518,7 @@ pub fn test_multi_asset_abort_zero_sudt_balance( } fn test_multi_asset_force_close( - context: &mut Context, + context: Rc>>, env: &perun::harness::Env, ) -> Result<(), perun::Error> { let (alice, bob) = ("alice", "bob"); @@ -452,15 +527,16 @@ fn test_multi_asset_force_close( Capacity::bytes(100)?.as_u64(), Capacity::bytes(100)?.as_u64(), ]; - let asset_funding = [ - 20u128, - 30u128, - ]; + let asset_funding = [20u128, 30u128]; let funding_agreement = test::FundingAgreement::new_with_capacities_and_sudt( parts.iter().cloned().zip(funding.iter().cloned()).collect(), &env.sample_udt_script, env.sample_udt_max_cap.as_u64(), - parts.iter().cloned().zip(asset_funding.iter().cloned()).collect(), + parts + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), ); create_channel_test(context, env, &parts, |chan| { chan.with(alice) @@ -475,7 +551,7 @@ fn test_multi_asset_force_close( chan.update(pay_sudt(Direction::BtoA, 10, 0)); chan.with(bob).dispute().expect("disputing channel"); - + chan.delay(env.challenge_duration); chan.with(bob).force_close().expect("force closing channel"); @@ -484,3 +560,1729 @@ fn test_multi_asset_force_close( Ok(()) }) } + +fn test_vc_start( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_START"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_progress_no_update( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_PROGRESS_NO_UPDATE"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + println!("opening vc dispute no progress on C_BI using Ingrid"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +// state update in vc but no update in lc +fn test_vc_progress_update1( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_PROGRESS_UPDATE1"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + + // simulate state update for vc + vc_ab.update(pay_ckbytes(Direction::AtoB, 30)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab) + .expect("only_vc_update"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +// state updates for both lc and vc +fn test_vc_progress_update2( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_PROGRESS_UPDATE2"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + + // simulate state update for vc + vc_ab.update(pay_ckbytes(Direction::AtoB, 30)); + //simulate state update for lc + chan_ai.with(alice).update(pay_ckbytes(Direction::AtoB, 30)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_lc_update(&mut vc_ab) + .expect("vc_lc_update"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_merge( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + let delay = 10u64; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_MERGE"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + let nonce = random::nonce(); + //First vc cell is created by Alice so she is the owner + let owner_participants1 = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_alice = owner_participants1.get(0).unwrap(); + + let mut vc_ab_1 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_alice, + ); + //Second owner is Bob so he is the owner of second vc cell + let owner_participants1 = funding_agreement_bi.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_bob = owner_participants1.get(0).unwrap(); + let mut vc_ab_2 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_bob, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_1.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_2.id().clone(), + &idx_map.parent2, + )); + + chan_ai + .with(alice) + .vc_start(&mut vc_ab_1) + .expect("vc_start by alice using C_AI"); + chan_bi.delay(delay); + chan_bi + .with(bob) + .vc_start(&mut vc_ab_2) + .expect("vc_start by bob using C_BI"); + + chan_bi + .with(ingrid) + .vc_merge(&vc_ab_1, &vc_ab_2, 0u8) + .expect("vc_merge"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_close1( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_CLOSE1"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + + // simulate state update for vc + vc_ab.update(pay_ckbytes(Direction::AtoB, 30)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab) + .expect("only_vc_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_with_dir = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab, &idx_map_with_dir) + .expect("vc_close1"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_close2( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_CLOSE2"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + + // simulate state update for vc + vc_ab.update(pay_ckbytes(Direction::AtoB, 30)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab) + .expect("only_vc_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_parent1 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab, &idx_map_parent1) + .expect("vc_close1"); + + let idx_map_parent2 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(1 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_bi + .with(ingrid) + .vc_close2(&mut vc_ab, &idx_map_parent2) + .expect("vc_close2"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_happy( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_HAPPY"); + chan_ai + .with(alice) + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_parent1 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab, &idx_map_parent1) + .expect("vc_close1"); + + let idx_map_parent2 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(1 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_bi + .with(ingrid) + .vc_close2(&mut vc_ab, &idx_map_parent2) + .expect("vc_close2"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_happy_multi_asset( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let asset_funding = [50u128, 50u128]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let asset_funding_vc = [20u128, 20u128]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities_and_sudt( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_ai + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities_and_sudt( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_bi + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities_and_sudt( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_ab + .iter() + .cloned() + .zip(asset_funding_vc.iter().cloned()) + .collect(), + ); + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_HAPPY_MULTI_ASSET"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + //Alice sends vc_start to tx and is thus the owner + let owner_participants = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner = owner_participants.get(0).unwrap(); + + let mut vc_ab = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &random::nonce(), + &owner, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab.id().clone(), + &idx_map.parent2, + )); + + chan_ai.with(alice).vc_start(&mut vc_ab).expect("vc_start"); + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab) + .expect("vc_progress_no_update"); + // simulate state update for vc + vc_ab.update(pay_ckbytes(Direction::AtoB, 30)); + vc_ab.update(pay_sudt(Direction::AtoB, 10, 0)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab) + .expect("only_vc_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_parent1 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab, &idx_map_parent1) + .expect("vc_close1"); + + let idx_map_parent2 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(1 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_bi + .with(ingrid) + .vc_close2(&mut vc_ab, &idx_map_parent2) + .expect("vc_close2"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_happy_with_merge( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + ); + + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + let delay = 10u64; + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_HAPPY_WITH_MERGE"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + let nonce = random::nonce(); + //First vc cell is created by Alice so she is the owner + let owner_participants1 = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_alice = owner_participants1.get(0).unwrap(); + + let mut vc_ab_1 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_alice, + ); + //Second owner is Bob so he is the owner of second vc cell + let owner_participants1 = funding_agreement_bi.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_bob = owner_participants1.get(0).unwrap(); + let mut vc_ab_2 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_bob, + ); + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_1.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_2.id().clone(), + &idx_map.parent2, + )); + + chan_ai + .with(alice) + .vc_start(&mut vc_ab_1) + .expect("vc_start"); + chan_bi.delay(delay); + + chan_bi.with(bob).vc_start(&mut vc_ab_2).expect("vc_start"); + + let result = chan_bi + .with(ingrid) + .vc_merge(&vc_ab_1, &vc_ab_2, 0u8) + .expect("vc_merge"); + + vc_ab_1.set_cell(result); + + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab_1) + .expect("vc_progress_no_update"); + + // simulate state update for vc + vc_ab_1.update(pay_ckbytes(Direction::AtoB, 30)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab_1) + .expect("only_vc_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_parent1 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab_1, &idx_map_parent1) + .expect("vc_close1"); + + let idx_map_parent2 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(1 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_bi + .with(ingrid) + .vc_close2(&mut vc_ab_1, &idx_map_parent2) + .expect("vc_close2"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} + +fn test_vc_happy_multi_asset_with_merge( + context: Rc>>, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob, ingrid) = ("alice", "bob", "ingrid"); + let alice_acc = random::account(alice); + let bob_acc = random::account(bob); + let ingrid_acc = random::account(ingrid); + + let parts_ai = [alice_acc.clone(), ingrid_acc.clone()]; + let parts_bi = [bob_acc.clone(), ingrid_acc.clone()]; + let parts_ab = [alice_acc.clone(), bob_acc.clone()]; + + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let asset_funding = [50u128, 50u128]; + + let funding_vc = [Capacity::bytes(50)?.as_u64(), Capacity::bytes(50)?.as_u64()]; + + let asset_funding_vc = [20u128, 20u128]; + + let funding_agreement_ai = test::FundingAgreement::new_with_capacities_and_sudt( + parts_ai + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_ai + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_bi = test::FundingAgreement::new_with_capacities_and_sudt( + parts_bi + .iter() + .cloned() + .zip(funding.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_bi + .iter() + .cloned() + .zip(asset_funding.iter().cloned()) + .collect(), + ); + + let funding_agreement_ab = test::FundingAgreement::new_with_capacities_and_sudt( + parts_ab + .iter() + .cloned() + .zip(funding_vc.iter().cloned()) + .collect(), + &env.sample_udt_script, + env.sample_udt_max_cap.as_u64(), + parts_ab + .iter() + .cloned() + .zip(asset_funding_vc.iter().cloned()) + .collect(), + ); + // Alice is proposer of C_AI + // Bob is proposer of C_IB + // Alice is proposer of VC_AB + // Parent1 is C_AI and Parent2 is C_IB + // idx_map maps participant roles from vc to lc + let idx_map = virtual_channel::VCIndexMap { + parent1: [0u8, 1u8], + parent2: [1u8, 0u8], + }; + + create_vc_channel_test( + context.clone(), + env, + &parts_ai, + &parts_bi, + |chan_ai, chan_bi| { + println!("TEST_VC_HAPPY_MULTI_ASSET_WITH_MERGE"); + chan_ai + .with(alice) //use borrow_mut in case of Rc cell + .open(&funding_agreement_ai) + .expect("opening channel"); + + chan_bi + .with(bob) + .open(&funding_agreement_bi) + .expect("opening channel"); + + chan_ai + .with(ingrid) + .fund(&funding_agreement_ai) + .expect("funding channel"); + + chan_bi + .with(ingrid) + .fund(&funding_agreement_bi) + .expect("funding channel"); + + let ctx = match context.try_lock() { + Ok(lock) => lock, + Err(_) => panic!("Failed to acquire lock on context"), + }; + let nonce = random::nonce(); + //First vc cell is created by Alice so she is the owner + let owner_participants1 = funding_agreement_ai.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_alice = owner_participants1.get(0).unwrap(); + + let mut vc_ab_1 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_alice, + ); + //Second owner is Bob so he is the owner of second vc cell + let owner_participants1 = funding_agreement_bi.mk_participants( + &mut ctx.borrow_mut(), + env, + env.min_capacity_no_script, + ); + let owner_bob = owner_participants1.get(0).unwrap(); + let mut vc_ab_2 = perun::virtual_channel::VirtualChannel::new( + &mut ctx.borrow_mut(), + env, + &parts_ab, + &funding_agreement_ab, + &chan_ai, + &chan_bi, + &idx_map, + &nonce, + &owner_bob, + ); + + drop(ctx); + // Simulate creating virtual channels + chan_ai.with(alice).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_1.id().clone(), + &idx_map.parent1, + )); + chan_bi.with(ingrid).update(update_virtual_channel( + &funding_agreement_ab, + vc_ab_2.id().clone(), + &idx_map.parent2, + )); + + chan_ai + .with(alice) + .vc_start(&mut vc_ab_1) + .expect("vc_start"); + chan_bi.delay(10u64); + chan_bi.with(bob).vc_start(&mut vc_ab_2).expect("vc_start"); + + let result = chan_bi + .with(ingrid) + .vc_merge(&vc_ab_1, &vc_ab_2, 0u8) + .expect("vc_merge"); + vc_ab_1.set_cell(result); + + chan_bi + .with(ingrid) + .vc_progress_no_update(&mut vc_ab_1) + .expect("vc_progress_no_update"); + // simulate state update for vc + vc_ab_1.update(pay_ckbytes(Direction::AtoB, 30)); + vc_ab_1.update(pay_sudt(Direction::AtoB, 10, 0)); + + // Alice posts higher version of vc state to the chain + chan_ai + .with(alice) + .vc_update_only(&mut vc_ab_1) + .expect("only_vc_update"); + + chan_ai.delay(env.challenge_duration); + chan_ai.delay(env.challenge_duration); + let idx_map_parent1 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(0 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_ai + .with(alice) + .vc_close1(&mut vc_ab_1, &idx_map_parent1) + .expect("vc_close1"); + + let idx_map_parent2 = virtual_channel::IdxMapWithDirection { + idx_map: idx_map.clone().invert_map(1 as usize), + direction: IdxMapDirection::LedgerChannelToVirtualChannel, + }; + chan_bi + .with(ingrid) + .vc_close2(&mut vc_ab_1, &idx_map_parent2) + .expect("vc_close2"); + chan_ai.assert(); + chan_bi.assert(); + Ok(()) + }, + ) +} diff --git a/payment-channel-ckb/devnet/deploy_contracts.sh b/payment-channel-ckb/devnet/deploy_contracts.sh index b93ca2f..26714f3 100755 --- a/payment-channel-ckb/devnet/deploy_contracts.sh +++ b/payment-channel-ckb/devnet/deploy_contracts.sh @@ -7,27 +7,74 @@ ACCOUNTS_DIR="accounts" PERUN_CONTRACTS_DIR="contracts" SYSTEM_SCRIPTS_DIR="system_scripts" DEVNET_DIR="$PWD" +DEPLOYMENT_INFO="info" +DEPLOYMENT_INFO_VC="info_vc" +MIGRATION="migrations/dev" +MIGRATION_VC="migrations_vc/dev" +genesis=$( cat ./accounts/genesis-2.txt | awk '/testnet/ {print$2}' | head -n 1) -genesis=$(cat $ACCOUNTS_DIR/genesis-2.txt | awk '/testnet/ { count++; if (count == 2) print $2}') +if [ -f "$DEPLOYMENT_INFO.json" ]; then + rm "$DEPLOYMENT_INFO.json" +fi cd $PERUN_CONTRACTS_DIR -if [ -d "migrations/dev" ]; then - rm -rf "migrations/dev" +if [ -d "./$MIGRATION" ]; then + rm -f ./$MIGRATION/*.json +else + mkdir -p "./$MIGRATION" +fi + +if [ -d "./$MIGRATION_VC" ]; then + rm -f ./$MIGRATION_VC/*.json +else + mkdir -p "./$MIGRATION_VC" fi +# rm ./$MIGRATION_VC/*.json + +echo "Deploying normal contracts..." expect << EOF -spawn capsule deploy --address $genesis --api "http://127.0.0.1:8114" --fee 1 -expect "Confirm deployment? (Yes/No)" -send "Yes\r" +spawn ckb-cli deploy gen-txs --deployment-config ./deployment/dev/deployment.toml --migration-dir ./$MIGRATION --from-address $genesis --sign-now --info-file $DEPLOYMENT_INFO.json expect "Password:" send "\r" expect eof + +spawn ckb-cli deploy sign-txs --from-account $genesis --add-signatures --info-file $DEPLOYMENT_INFO.json +expect "Password:" +send "\r" +expect eof + +spawn ckb-cli deploy apply-txs --migration-dir ./$MIGRATION --info-file $DEPLOYMENT_INFO.json +expect eof EOF +echo "Deploying normal contracts done." +echo "Waiting for 10 seconds before deploying vc contracts..." +sleep 10.0 +echo "Deplyoing vc contracts..." +expect << EOF +spawn ckb-cli deploy gen-txs --deployment-config ./deployment/dev/deployment_vc.toml --migration-dir ./$MIGRATION_VC --from-address $genesis --sign-now --info-file $DEPLOYMENT_INFO_VC.json +expect "Password:" +send "\r" +expect eof + +spawn ckb-cli deploy sign-txs --from-account $genesis --add-signatures --info-file $DEPLOYMENT_INFO_VC.json +expect "Password:" +send "\r" +expect eof + +spawn ckb-cli deploy apply-txs --migration-dir ./$MIGRATION_VC --info-file $DEPLOYMENT_INFO_VC.json +expect eof +EOF + +mv ./$DEPLOYMENT_INFO.json ./.. +mv ./$DEPLOYMENT_INFO_VC.json ./.. + +echo "Deploying contracts done." # Fetch default contracts: cd $DEVNET_DIR - +echo "Fetching default contracts..." if [ -d "$SYSTEM_SCRIPTS_DIR" ]; then rm -rf "$SYSTEM_SCRIPTS_DIR" fi @@ -38,14 +85,21 @@ mkdir -p "$SYSTEM_SCRIPTS_DIR" ## so we have to do that in a second pass... ckb-cli util genesis-scripts --output-format json \ | sed 's/code_hash: \(.*\)/code_hash: \"\1\"/; s/tx_hash: \(.*\)/tx_hash: \"\1\"/' \ - | sed 's/"index": \([0-9]\+\),/echo "\\"index\\": $(python -c "print(\\\"\\\\\\"{}\\\\\\"\\\".format(hex(\1)))"),";/e' \ + | sed 's/"index": \([0-9]\+\),/echo "\\"index\\": $(python3 -c "print(\\\"\\\\\\"{}\\\\\\"\\\".format(hex(\1)))"),";/e' \ | jq . > "$SYSTEM_SCRIPTS_DIR/default_scripts.json" +echo "Fetching default contracts done." + cd $DEVNET_DIR +echo "Fetching genesis cell..." +timestamp=$(date '+%Y-%m-%d-%H%M%S') -SUDT_TX_HASH=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[3].tx_hash) -SUDT_TX_INDEX=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[3].index) -SUDT_DATA_HASH=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[3].data_hash) +rm ./$DEPLOYMENT_INFO.json +rm ./$DEPLOYMENT_INFO_VC.json +SUDT_TX_HASH=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[0].tx_hash) +SUDT_TX_INDEX=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[0].index) +SUDT_DATA_HASH=$(cat ./contracts/migrations/dev/*.json | jq .cell_recipes[0].data_hash) +echo "Fetching genesis cell done." # TODO: This only works as long as the tx index is 0-9. -jq ".items.sudt.script_id.code_hash = $SUDT_DATA_HASH | .items.sudt.cell_dep.out_point.tx_hash = $SUDT_TX_HASH | .items.sudt.cell_dep.out_point.index = \"0x$SUDT_TX_INDEX\"" ./sudt-celldep-template.json > $SYSTEM_SCRIPTS_DIR/sudt-celldep.json +jq ".items.sudt.script_id.code_hash = $SUDT_DATA_HASH | .items.sudt.cell_dep.out_point.tx_hash = $SUDT_TX_HASH | .items.sudt.cell_dep.out_point.index = \"0x$SUDT_TX_INDEX\"" ./sudt-celldep-template.json > $SYSTEM_SCRIPTS_DIR/sudt-celldep.json \ No newline at end of file diff --git a/payment-channel-ckb/devnet/devnet-session.yaml b/payment-channel-ckb/devnet/devnet-session.yaml index c266d19..8e73dde 100644 --- a/payment-channel-ckb/devnet/devnet-session.yaml +++ b/payment-channel-ckb/devnet/devnet-session.yaml @@ -4,23 +4,23 @@ windows: - layout: tiled panes: - shell_command: - - ckb run + - ckb run - shell_command: - - sleep 3.0 - - ckb miner + - sleep 1.0 + - ckb miner - shell_command: - - sleep 3.0 - - ./print_accounts.sh + - sleep 1.0 + - ./print_accounts.sh - shell_command: - - sleep 6.0 - - expect fund_accounts.expect && ckb-cli + - sleep 3.0 + - expect fund_accounts.expect && ckb-cli - panes: - shell_command: - - sleep 10.0 - - ./deploy_contracts.sh - - echo "Waiting 15 seconds before funding SUDTs" - - sleep 15.0 - - ./sudt_helper.sh fund - - echo "Waiting 10 seconds before listing SUDT account balances" - - sleep 10.0 - - ./sudt_helper.sh balances + - sleep 3.0 + - ./deploy_contracts.sh + - echo "Waiting 15 seconds before funding SUDTs" + - sleep 1.0 + - ./sudt_helper.sh fund + - echo "Waiting 10 seconds before listing SUDT account balances" + - sleep 2.0 + - ./sudt_helper.sh balances diff --git a/payment-channel-ckb/devnet/setup-devnet.sh b/payment-channel-ckb/devnet/setup-devnet.sh index 7625586..5c670d3 100755 --- a/payment-channel-ckb/devnet/setup-devnet.sh +++ b/payment-channel-ckb/devnet/setup-devnet.sh @@ -38,9 +38,7 @@ fi # Build all required contracts for Perun. DEVNET=$(pwd) cd $PERUN_CONTRACTS_DIR -capsule build --release -# If debug contracts are wanted: -# capsule build +source ./setup_env.sh build && make build cd $DEVNET # Genesis cell #1 @@ -76,12 +74,16 @@ ckb init --chain dev --ba-arg $MINER_LOCK_ARG --ba-message "0x" --force # Make the scripts owned by the miner. sed -i "s/args =.*$/args = \"$MINER_LOCK_ARG\"/" $PERUN_CONTRACTS_DIR/deployment/dev/deployment.toml +sed -i "s/args =.*$/args = \"$MINER_LOCK_ARG\"/" $PERUN_CONTRACTS_DIR/deployment/dev/deployment_vc.toml # Use the debug versions of the contracts. # sed -i "s/release/debug/" $PERUN_CONTRACTS_DIR/deployment/dev/deployment.toml # Adjust miner config to process blocks faster. sed -i 's/value = 5000/value = 1000/' ckb-miner.toml +# Fast mining config +sed -i '/\[mining\]/a always_submit_block = true' ckb.toml + # Reduce epoch length to 10 blocks. sed -i 's/genesis_epoch_length = 1000/genesis_epoch_length = 10/' specs/dev.toml sed -i '/\[params\]/a\ @@ -93,4 +95,4 @@ sed -i '/filter = "info"/ s/filter = "info"/filter = "debug"/' ckb.toml sed -i 's/max_tx_verify_cycles = 70_000_000/max_tx_verify_cycles = 100_000_000/' ckb.toml # Increase max_request_body_size to allow for debug contracts (large in size) # to be deployed. -sed -i 's/max_request_body_size =.*$/max_request_body_size = 104857600/' ckb.toml +sed -i 's/max_request_body_size =.*$/max_request_body_size = 104857600/' ckb.toml \ No newline at end of file diff --git a/payment-channel-ckb/go.mod b/payment-channel-ckb/go.mod index 15f24cf..bba944f 100644 --- a/payment-channel-ckb/go.mod +++ b/payment-channel-ckb/go.mod @@ -7,10 +7,10 @@ toolchain go1.23.4 require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 - github.com/perun-network/perun-libp2p-wire v0.2.2 + github.com/perun-network/perun-libp2p-wire v1.0.1 github.com/stretchr/testify v1.10.0 - perun.network/go-perun v0.12.0 - perun.network/perun-ckb-backend v0.0.0-20241024114309-500054212d66 + perun.network/go-perun v0.13.1-0.20250528124331-21b590b655d3 + perun.network/perun-ckb-backend v0.2.1-0.20250603085027-d25a5eb09110 polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 ) @@ -51,7 +51,7 @@ require ( github.com/koron/go-ssdp v0.0.5 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.2.0 // indirect - github.com/libp2p/go-libp2p v0.41.0 // indirect + github.com/libp2p/go-libp2p v0.41.1 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-netroute v0.2.2 // indirect @@ -82,14 +82,14 @@ require ( github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/dtls/v3 v3.0.4 // indirect - github.com/pion/ice/v4 v4.0.6 // indirect + github.com/pion/ice/v4 v4.0.8 // indirect github.com/pion/interceptor v0.1.37 // indirect github.com/pion/logging v0.2.3 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.15 // indirect github.com/pion/rtp v1.8.11 // indirect - github.com/pion/sctp v1.8.36 // indirect + github.com/pion/sctp v1.8.37 // indirect github.com/pion/sdp/v3 v3.0.10 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun v0.6.1 // indirect @@ -100,12 +100,12 @@ require ( github.com/pion/webrtc/v4 v4.0.10 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.21.0 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.50.0 // indirect + github.com/quic-go/quic-go v0.50.1 // indirect github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -121,17 +121,17 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + golang.org/x/tools v0.32.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.4.0 // indirect ) -replace github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 => github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20241016165355-d1c9686fe018 +replace github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 => github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20250729062233-916bd7327fac diff --git a/payment-channel-ckb/go.sum b/payment-channel-ckb/go.sum index 1077236..d16333c 100644 --- a/payment-channel-ckb/go.sum +++ b/payment-channel-ckb/go.sum @@ -108,8 +108,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -173,8 +171,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= -github.com/libp2p/go-libp2p v0.41.0 h1:JRaD39dqf/tBBGapJ0T38N73vOaDCsWgcx3mE6HgXWk= -github.com/libp2p/go-libp2p v0.41.0/go.mod h1:Be8QYqC4JW6Xq8buukNeoZJjyT1XUDcGoIooCHm1ye4= +github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= +github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -255,10 +253,10 @@ github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20241016165355-d1c9686fe018 h1:oURRmvOUVKfNFqhqBonJY1VHKxziyhw4zkL0QLj+m3M= -github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20241016165355-d1c9686fe018/go.mod h1:nPpBML8fuaM1NgkKCwv2gSHiCv+xKH43fu8LA9LOQUg= -github.com/perun-network/perun-libp2p-wire v0.2.2 h1:PlZxShX9lTQrzO9EUP/usTItMaKrEoDbqwho4TnJe/4= -github.com/perun-network/perun-libp2p-wire v0.2.2/go.mod h1:Tk75w71TG1a7xY1WkdGTJi+YEnOFTHVOBIuQEEohZfU= +github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20250729062233-916bd7327fac h1:fqMvGP4wpFP5OoZkDTSFPvVWP/7F/HMhCujxQwoxbAA= +github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20250729062233-916bd7327fac/go.mod h1:nPpBML8fuaM1NgkKCwv2gSHiCv+xKH43fu8LA9LOQUg= +github.com/perun-network/perun-libp2p-wire v1.0.1 h1:pNeCjGWddD0Fb8y+jdn4XQVoN/UoXdUZbjfBgCI8KzQ= +github.com/perun-network/perun-libp2p-wire v1.0.1/go.mod h1:hIyG3pSboLYcaQr2yzpxNb6izvSsHi6iC50GaAfwvvE= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= @@ -266,8 +264,8 @@ github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= -github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM= -github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= @@ -281,8 +279,8 @@ github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= -github.com/pion/sctp v1.8.36 h1:owNudmnz1xmhfYje5L/FCav3V9wpPRePHle3Zi+P+M0= -github.com/pion/sctp v1.8.36/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= @@ -307,8 +305,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= -github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= @@ -320,8 +318,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo= -github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= +github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -380,8 +378,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= @@ -431,11 +427,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -447,8 +443,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -471,8 +467,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -488,8 +484,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -517,8 +513,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -534,8 +530,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -554,8 +550,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -576,8 +572,8 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -598,10 +594,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= -perun.network/go-perun v0.12.0 h1:9Cdk5nHFYkegk+2FbqO9SjvgzUvduVWUiiJXrWkAwBA= -perun.network/go-perun v0.12.0/go.mod h1:uH8iwi75alXDizxxDzH0A+6uqXPbagCpKfl8ECMv/cA= -perun.network/perun-ckb-backend v0.0.0-20241024114309-500054212d66 h1:0k3zF5+xY7TXbTRbCsrSqPJ7I6hRdu/6mHxRwUtnakU= -perun.network/perun-ckb-backend v0.0.0-20241024114309-500054212d66/go.mod h1:cFfA6/mX8ePTuFrd5cyHhzx1H8hnHs99WrLB9LS+Xbo= +perun.network/go-perun v0.13.1-0.20250528124331-21b590b655d3 h1:vW6QhIoMwycG0fofZZfhJ4I2v1fc1Dm/VZka1RJilq8= +perun.network/go-perun v0.13.1-0.20250528124331-21b590b655d3/go.mod h1:uH8iwi75alXDizxxDzH0A+6uqXPbagCpKfl8ECMv/cA= +perun.network/perun-ckb-backend v0.2.1-0.20250603085027-d25a5eb09110 h1:NoQYXbpIrOSitgWLkKCr66iMMyeCABb8kTXSNkL45WE= +perun.network/perun-ckb-backend v0.2.1-0.20250603085027-d25a5eb09110/go.mod h1:e2KkWOOPPYGFF6iRBMEhhL8ZmoaLRHntNnZeFt/Dt1Y= polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 h1:iA5GzEa/hHfVlQpimEjPV09NATwHXxSjWNB0VVodtew= polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37/go.mod h1:XUBrNtqgEhN3EEOP/5gh7IBd3xVHKidCjXDZfl9+kMU= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= diff --git a/payment-channel-ckb/main.go b/payment-channel-ckb/main.go index 52cc3a5..0c50136 100644 --- a/payment-channel-ckb/main.go +++ b/payment-channel-ckb/main.go @@ -15,68 +15,31 @@ package main import ( - "errors" "fmt" - "io/ioutil" "log" - "math/big" "math/rand" "time" "github.com/nervosnetwork/ckb-sdk-go/v2/types" "github.com/perun-network/perun-libp2p-wire/p2p" "perun.network/go-perun/channel" - "perun.network/go-perun/channel/persistence/keyvalue" + ckbchannel "perun.network/perun-ckb-backend/channel" "perun.network/perun-ckb-backend/channel/asset" - "perun.network/perun-ckb-backend/wallet" "perun.network/perun-examples/payment-channel-ckb/client" - "perun.network/perun-examples/payment-channel-ckb/deployment" - "polycry.pt/poly-go/sortedkv/memorydb" ) const ( rpcNodeURL = "http://localhost:8114" - Network = types.NetworkTest + Network = types.NetworkTest // Network to use for the CKB client ) func main() { //Setup devnet environment - log.Println("Deploying Devnet") - sudtOwnerLockArg, err := parseSUDTOwnerLockArg("./devnet/accounts/sudt-owner-lock-hash.txt") - if err != nil { - log.Fatalf("error getting SUDT owner lock arg: %v", err) - } - d, _, err := deployment.GetDeployment("./devnet/contracts/migrations/dev/", "./devnet/system_scripts", sudtOwnerLockArg) - if err != nil { - log.Fatalf("error getting deployment: %v", err) - } - - //Setup wallets - log.Println("Creating wallets") - w := wallet.NewEphemeralWallet() - - keyAlice, err := deployment.GetKey("./devnet/accounts/alice.pk") - if err != nil { - log.Fatalf("error getting alice's private key: %v", err) - } - keyBob, err := deployment.GetKey("./devnet/accounts/bob.pk") - if err != nil { - log.Fatalf("error getting bob's private key: %v", err) - } - aliceAccount := wallet.NewAccountFromPrivateKey(keyAlice) - bobAccount := wallet.NewAccountFromPrivateKey(keyBob) - - err = w.AddAccount(aliceAccount) - if err != nil { - log.Fatalf("error adding alice's account: %v", err) - } - err = w.AddAccount(bobAccount) - if err != nil { - log.Fatalf("error adding bob's account: %v", err) - } + setup := NewSetup() + log.Println("Setting up payment channel clients") aliceWireAcc := p2p.NewRandomAccount(rand.New(rand.NewSource(time.Now().UnixNano()))) - aliceNet, err := p2p.NewP2PBus(aliceWireAcc) + aliceNet, err := p2p.NewP2PBus(ckbchannel.CKBBackendID, aliceWireAcc) if err != nil { log.Fatalf("creating p2p net: %v", err) } @@ -84,20 +47,14 @@ func main() { aliceListener := aliceNet.Listener go aliceBus.Listen(aliceListener) - log.Println("Setting up payment channel clients") - - //Setup Payment Clients - prAlice := keyvalue.NewPersistRestorer(memorydb.NewDatabase()) - alice, err := client.NewPaymentClient( "Alice", Network, - d, + setup.Deployment, rpcNodeURL, - aliceAccount, - *keyAlice, - w, - prAlice, + setup.WalletAccs[0], + *setup.AccKeys[0], + setup.Wallets[0], aliceWireAcc.Address(), aliceNet, ) @@ -105,9 +62,8 @@ func main() { log.Fatalf("error creating alice's client: %v", err) } - prBob := keyvalue.NewPersistRestorer(memorydb.NewDatabase()) bobWireAcc := p2p.NewRandomAccount(rand.New(rand.NewSource(time.Now().UnixNano()))) - bobNet, err := p2p.NewP2PBus(bobWireAcc) + bobNet, err := p2p.NewP2PBus(ckbchannel.CKBBackendID, bobWireAcc) if err != nil { log.Fatalf("creating p2p net: %v", err) } @@ -118,12 +74,11 @@ func main() { bob, err := client.NewPaymentClient( "Bob", Network, - d, + setup.Deployment, rpcNodeURL, - bobAccount, - *keyBob, - w, - prBob, + setup.WalletAccs[1], + *setup.AccKeys[1], + setup.Wallets[1], bobWireAcc.Address(), bobNet, ) @@ -131,21 +86,13 @@ func main() { log.Fatalf("error creating bob's client: %v", err) } - ckbAsset := asset.Asset{ - IsCKBytes: true, - SUDT: nil, - } - fmt.Println("Alice Balance:", alice.GetBalances()) fmt.Println("Bob Balance:", bob.GetBalances()) //Open Channel between Alice and Bob log.Println("Opening channel and depositing funds") chAlice := alice.OpenChannel(bob.WireAddress(), bob.PeerID(), map[channel.Asset]float64{ - &asset.Asset{ - IsCKBytes: true, - SUDT: nil, - }: 100.0, + setup.CKBAsset: 100.0, }) log.Println("Alice sent proposal") @@ -153,29 +100,24 @@ func main() { chBob := bob.AcceptedChannel() log.Println("Bob accepted proposal") - printBalances(chAlice, ckbAsset) + assets := []asset.Asset{*setup.CKBAsset} + printBalances(chAlice, assets) log.Println("Sending payments....") //Alice sends payment chAlice.SendPayment(map[channel.Asset]float64{ - &ckbAsset: 10.0, + setup.CKBAsset: 10.0, }) log.Println("Alice sent Bob a payment") - printBalances(chAlice, ckbAsset) + printBalances(chAlice, assets) //Bob sends payment chBob.SendPayment(map[channel.Asset]float64{ - &ckbAsset: 10.0, + setup.CKBAsset: 5.0, }) log.Println("Bob sent Alice a payment") - printBalances(chAlice, ckbAsset) - - chAlice.SendPayment(map[channel.Asset]float64{ - &ckbAsset: 10.0, - }) - log.Println("Alice sent Bob a payment") - printBalances(chAlice, ckbAsset) + printBalances(chAlice, assets) log.Println("Payments completed") @@ -189,48 +131,3 @@ func main() { log.Println("Clients shutdown, exiting method") } - -func printBalances(ch *client.PaymentChannel, asset asset.Asset) { - chAlloc := ch.State().Allocation - - // Constants for formatting CKBytes - const ckbyteConversionFactor = 100_000_000 // 1 CKByte = 100,000,000 smallest units - - // Log general information - log.Println("=== Allocation Balances ===") - - // Get Alice's balance (participant 0) - aliceBalance := chAlloc.Balance(0, &asset) - aliceBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(aliceBalance), big.NewFloat(ckbyteConversionFactor)) - - // Get Bob's balance (participant 1) - bobBalance := chAlloc.Balance(1, &asset) - bobBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(bobBalance), big.NewFloat(ckbyteConversionFactor)) - - // Print Alice's balance - log.Printf("Alice's allocation: %s CKBytes", aliceBalanceCKBytes.Text('f', 2)) - - // Print Bob's balance - log.Printf("Bob's allocation: %s CKBytes", bobBalanceCKBytes.Text('f', 2)) - - // Calculate the total balance - totalBalance := new(big.Int).Add(aliceBalance, bobBalance) - totalBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(totalBalance), big.NewFloat(ckbyteConversionFactor)) - - // Print the total channel balance - log.Printf("Total channel balance: %s CKBytes", totalBalanceCKBytes.Text('f', 2)) - - log.Println("===========================") -} - -func parseSUDTOwnerLockArg(pathToSUDTOwnerLockArg string) (string, error) { - b, err := ioutil.ReadFile(pathToSUDTOwnerLockArg) - if err != nil { - return "", fmt.Errorf("reading sudt owner lock arg from file: %w", err) - } - sudtOwnerLockArg := string(b) - if sudtOwnerLockArg == "" { - return "", errors.New("sudt owner lock arg not found in file") - } - return sudtOwnerLockArg, nil -} diff --git a/payment-channel-ckb/package.json b/payment-channel-ckb/package.json index 629e7c2..6bf5532 100644 --- a/payment-channel-ckb/package.json +++ b/payment-channel-ckb/package.json @@ -2,4 +2,4 @@ "dependencies": { "secp256k1": "^5.0.0" } -} +} \ No newline at end of file diff --git a/payment-channel-ckb/payment-channel-ckb b/payment-channel-ckb/payment-channel-ckb deleted file mode 100644 index 16d8678..0000000 Binary files a/payment-channel-ckb/payment-channel-ckb and /dev/null differ diff --git a/payment-channel-ckb/util.go b/payment-channel-ckb/util.go new file mode 100644 index 0000000..2f3a0de --- /dev/null +++ b/payment-channel-ckb/util.go @@ -0,0 +1,166 @@ +package main + +import ( + "errors" + "fmt" + "log" + "math/big" + "os" + + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "perun.network/perun-ckb-backend/backend" + "perun.network/perun-ckb-backend/channel/asset" + "perun.network/perun-ckb-backend/channel/test" + "perun.network/perun-ckb-backend/wallet" + ckbwallet "perun.network/perun-ckb-backend/wallet" + "perun.network/perun-examples/payment-channel-ckb/client" + "perun.network/perun-examples/payment-channel-ckb/deployment" +) + +const ( + sudtMaxCapacity = 200_00_000_000 // 200 ckb +) + +// Setup contains all the necessary information for CKB payment channel setup. +type Setup struct { + Deployment backend.Deployment + SUDTInfo deployment.SUDTInfo + Wallets []*ckbwallet.EphemeralWallet + WalletAccs []*ckbwallet.Account + CKBAsset *asset.Asset + SudtAsset *asset.Asset + AccKeys []*secp256k1.PrivateKey +} + +// NewSetup creates a new Setup instance with the provided parameters. +func NewSetup() *Setup { + log.Println("Initializing CKB payment channel setup") + + sudtOwnerLockArg, err := parseSUDTOwnerLockArg("./devnet/accounts/sudt-owner-lock-hash.txt") + if err != nil { + log.Fatalf("error getting SUDT owner lock arg: %v", err) + } + + d, sudtInfo, err := deployment.GetDeployment("./devnet/contracts/migrations/dev/", "./devnet/contracts/migrations_vc/dev/", "./devnet/system_scripts", sudtOwnerLockArg) + if err != nil { + log.Fatalf("error getting deployment: %v", err) + } + + //Setup wallets + log.Println("Creating wallets") + wAlice := wallet.NewEphemeralWallet() + wBob := wallet.NewEphemeralWallet() + + keyAlice, err := test.GetKey("./devnet/accounts/alice.pk") + if err != nil { + log.Fatalf("error getting alice's private key: %v", err) + } + keyBob, err := test.GetKey("./devnet/accounts/bob.pk") + if err != nil { + log.Fatalf("error getting bob's private key: %v", err) + } + + aliceAccount := wallet.NewAccountFromPrivateKey(keyAlice) + bobAccount := wallet.NewAccountFromPrivateKey(keyBob) + + err = wAlice.AddAccount(aliceAccount) + if err != nil { + log.Fatalf("error adding alice's account: %v", err) + } + err = wBob.AddAccount(bobAccount) + if err != nil { + log.Fatalf("error adding bob's account: %v", err) + } + + ckbAsset := &asset.Asset{ + IsCKBytes: true, + SUDT: nil, + } + + sudtAsset := &asset.Asset{ + IsCKBytes: false, + SUDT: asset.NewSUDT(*sudtInfo.Script, uint64(sudtMaxCapacity)), + } + return &Setup{ + Deployment: d, + SUDTInfo: sudtInfo, + Wallets: []*ckbwallet.EphemeralWallet{wAlice, wBob}, + WalletAccs: []*ckbwallet.Account{aliceAccount, bobAccount}, + CKBAsset: ckbAsset, + SudtAsset: sudtAsset, + AccKeys: []*secp256k1.PrivateKey{keyAlice, keyBob}, + } +} + +func parseSUDTOwnerLockArg(pathToSUDTOwnerLockArg string) (string, error) { + b, err := os.ReadFile(pathToSUDTOwnerLockArg) + if err != nil { + return "", fmt.Errorf("reading sudt owner lock arg from file: %w", err) + } + sudtOwnerLockArg := string(b) + if sudtOwnerLockArg == "" { + return "", errors.New("sudt owner lock arg not found in file") + } + return sudtOwnerLockArg, nil +} + +func printBalances(ch *client.PaymentChannel, assets []asset.Asset) { + chAlloc := ch.State().Allocation + + // Constants for formatting CKBytes + const ckbyteConversionFactor = 100_000_000 // 1 CKByte = 100,000,000 smallest units + const sudtConversionFactor = 1 // SUDT is already in the smallest unit + + // Log general information + log.Println("=== Allocation Balances ===") + for _, asset := range assets { + if asset.IsCKBytes { + + // Get Alice's balance (participant 0) + aliceBalance := chAlloc.Balance(0, &asset) + aliceBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(aliceBalance), big.NewFloat(ckbyteConversionFactor)) + + // Get Bob's balance (participant 1) + bobBalance := chAlloc.Balance(1, &asset) + bobBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(bobBalance), big.NewFloat(ckbyteConversionFactor)) + + // Print Alice's balance + log.Printf("Alice's allocation: %s CKBytes", aliceBalanceCKBytes.Text('f', 2)) + + // Print Bob's balance + log.Printf("Bob's allocation: %s CKBytes", bobBalanceCKBytes.Text('f', 2)) + + // Calculate the total balance + totalBalance := new(big.Int).Add(aliceBalance, bobBalance) + totalBalanceCKBytes := new(big.Float).Quo(new(big.Float).SetInt(totalBalance), big.NewFloat(ckbyteConversionFactor)) + + // Print the total channel balance + log.Printf("Total channel balance: %s CKBytes", totalBalanceCKBytes.Text('f', 2)) + + log.Println("===========================") + } else { + // Get Alice's balance (participant 0) + aliceBalance := chAlloc.Balance(0, &asset) + aliceBalanceSUDTs := new(big.Float).Quo(new(big.Float).SetInt(aliceBalance), big.NewFloat(sudtConversionFactor)) + + // Get Bob's balance (participant 1) + bobBalance := chAlloc.Balance(1, &asset) + bobBalanceSUDTs := new(big.Float).Quo(new(big.Float).SetInt(bobBalance), big.NewFloat(sudtConversionFactor)) + + // Print Alice's balance + log.Printf("Alice's allocation: %s SUDT", aliceBalanceSUDTs.Text('f', 2)) + + // Print Bob's balance + log.Printf("Bob's allocation: %s SUDT", bobBalanceSUDTs.Text('f', 2)) + + // Calculate the total balance + totalBalance := new(big.Int).Add(aliceBalance, bobBalance) + totalBalanceSUDTs := new(big.Float).Quo(new(big.Float).SetInt(totalBalance), big.NewFloat(sudtConversionFactor)) + + // Print the total channel balance + log.Printf("Total channel balance: %s SUDT", totalBalanceSUDTs.Text('f', 2)) + + log.Println("===========================") + } + } +}