diff --git a/payment-channel-ckb/.gitignore b/payment-channel-ckb/.gitignore new file mode 100644 index 0000000..336fc31 --- /dev/null +++ b/payment-channel-ckb/.gitignore @@ -0,0 +1,28 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# log files +*.log + +perun-ckb-demo + +# Dependency directories (remove the comment below to include it) +# vendor/ +devnet/accounts +devnet/data +devnet/specs +devnet/ckb-miner.toml +devnet/ckb.toml +devnet/default.db-options +devnet/system_scripts +.vscode/ diff --git a/payment-channel-ckb/.gitmodules b/payment-channel-ckb/.gitmodules new file mode 100644 index 0000000..5bc5ff8 --- /dev/null +++ b/payment-channel-ckb/.gitmodules @@ -0,0 +1,3 @@ +[submodule "devnet/contracts"] + path = devnet/contracts + url = git@github.com:perun-network/perun-ckb-contract diff --git a/payment-channel-ckb/client/balances.go b/payment-channel-ckb/client/balances.go new file mode 100644 index 0000000..a322278 --- /dev/null +++ b/payment-channel-ckb/client/balances.go @@ -0,0 +1,89 @@ +package client + +import ( + "context" + "encoding/binary" + "fmt" + "log" + "math" + "math/big" + "strconv" + "time" + + "github.com/nervosnetwork/ckb-sdk-go/v2/indexer" + "github.com/nervosnetwork/ckb-sdk-go/v2/types" + "perun.network/perun-ckb-backend/wallet/address" +) + +type BalanceExtractor func(*indexer.LiveCell) *big.Int + +func ckbBalanceExtractor(cell *indexer.LiveCell) *big.Int { + return new(big.Int).SetUint64(cell.Output.Capacity) +} + +func sudtBalanceExtractor(cell *indexer.LiveCell) *big.Int { + if len(cell.OutputData) != 16 { + return big.NewInt(0) + } + return new(big.Int).SetUint64(binary.LittleEndian.Uint64(cell.OutputData)) +} + +func (p *PaymentClient) PollBalances() { + defer log.Println("PollBalances: stopped") + pollingInterval := time.Second + searchKey := &indexer.SearchKey{ + Script: address.AsParticipant(p.Account.Address()).PaymentScript, + ScriptType: types.ScriptTypeLock, + ScriptSearchMode: types.ScriptSearchModeExact, + Filter: nil, + WithData: true, + } + log.Println("PollBalances") + updateBalance := func() { + ctx, _ := context.WithTimeout(context.Background(), pollingInterval) + + cells, err := p.rpcClient.GetCells(ctx, searchKey, indexer.SearchOrderDesc, math.MaxUint32, "") + if err != nil { + log.Println("balance poll error: ", err) + return + } + ckbBalance := big.NewInt(0) + sudtBalance := big.NewInt(0) + for _, cell := range cells.Objects { + ckbBalance = new(big.Int).Add(ckbBalance, ckbBalanceExtractor(cell)) + sudtBalance = new(big.Int).Add(sudtBalance, sudtBalanceExtractor(cell)) + } + + p.balanceMutex.Lock() + if ckbBalance.Cmp(p.balance) != 0 || sudtBalance.Cmp(p.sudtBalance) != 0 { + // Update ckb balance. + p.balance = ckbBalance + //ckbBal := p.balance.Int64() + + // Update sudt balance. + p.sudtBalance = sudtBalance + + p.balanceMutex.Unlock() + //p.NotifyAllBalance(ckbBal) // TODO: Update demo tui to allow for big.Int balances + } else { + p.balanceMutex.Unlock() + } + } + updateBalance() + //return "CKbytes: " + p.balance.String() + ", SUDT: " + p.sudtBalance.String() + /* + // Poll the balance every 5 seconds. + for { + updateBalance() + time.Sleep(pollingInterval) + } + */ +} + +func FormatBalance(ckbBal, sudtBal *big.Int) string { + log.Printf("balances: ckb = %s || sudt = %s", ckbBal.String(), sudtBal.String()) + balCKByte, _ := ShannonToCKByte(ckbBal).Float64() + return fmt.Sprintf("[green]%s\t[yellow]%s[white]", + strconv.FormatFloat(balCKByte, 'f', 2, 64)+" CKByte", + fmt.Sprintf("%v", sudtBal.Int64())+" SUDT") +} diff --git a/payment-channel-ckb/client/channel.go b/payment-channel-ckb/client/channel.go new file mode 100644 index 0000000..05a5b61 --- /dev/null +++ b/payment-channel-ckb/client/channel.go @@ -0,0 +1,91 @@ +package client + +import ( + "context" + "fmt" + "math/big" + + "perun.network/go-perun/channel" + "perun.network/go-perun/client" +) + +type PaymentChannel struct { + ch *client.Channel + assets []channel.Asset +} + +// newPaymentChannel creates a new payment channel. +func newPaymentChannel(ch *client.Channel, assets []channel.Asset) *PaymentChannel { + return &PaymentChannel{ + ch: ch, + assets: assets, + } +} + +func (c PaymentChannel) State() *channel.State { + return c.ch.State().Clone() +} + +func (c PaymentChannel) SendPayment(amounts map[channel.Asset]float64) { + // Transfer the given amount from us to peer. + // Use UpdateBy to update the channel state. + err := c.ch.Update(context.TODO(), func(state *channel.State) { + actor := c.ch.Idx() + peer := 1 - actor + //fmt.Println("Send payment handler called") + for a, amount := range amounts { + fmt.Println(a) + fmt.Println(amount) + if amount < 0 { + continue + } + /* + switch a := a.(type) { + case *asset.Asset: + if a.IsCKBytes { + fmt.Println("inside condition isCKBytes") + shannonAmount := CKByteToShannon(big.NewFloat(amount)) + state.Allocation.TransferBalance(actor, peer, a, shannonAmount) + } else { + fmt.Println("inside if conditional !isCKBytes") + intAmount := new(big.Int).SetUint64(uint64(amount)) + state.Allocation.TransferBalance(actor, peer, a, intAmount) + } + } + */ + + shannonAmount := CKByteToShannon(big.NewFloat(amount)) + state.Allocation.TransferBalance(actor, peer, a, shannonAmount) + + } + + }) + if err != nil { + panic(err) + } + if err != nil { + panic(err) // We panic on error to keep the code simple. + } +} + +// Settle settles the payment channel and withdraws the funds. +func (c PaymentChannel) Settle() { + // Finalize the channel to enable fast settlement. + if !c.ch.State().IsFinal { + err := c.ch.Update(context.TODO(), func(state *channel.State) { + state.IsFinal = true + }) + if err != nil { + panic(err) + } + } + + // Settle concludes the channel and withdraws the funds. + err := c.ch.Settle(context.TODO()) + if err != nil { + panic(err) + } + + // Close frees up channel resources. + c.ch.Close() +} diff --git a/payment-channel-ckb/client/client.go b/payment-channel-ckb/client/client.go new file mode 100644 index 0000000..7564e30 --- /dev/null +++ b/payment-channel-ckb/client/client.go @@ -0,0 +1,261 @@ +package client + +import ( + "context" + "fmt" + "log" + "math/big" + + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "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/adjudicator" + "perun.network/perun-ckb-backend/channel/asset" + "perun.network/perun-ckb-backend/channel/funder" + ckbclient "perun.network/perun-ckb-backend/client" + "perun.network/perun-ckb-backend/wallet" + "perun.network/perun-ckb-backend/wallet/address" + "polycry.pt/poly-go/sync" +) + +type PaymentClient struct { + balanceMutex sync.Mutex + Name string + balance *big.Int + sudtBalance *big.Int + Account *wallet.Account + wAddr wire.Address + Network types.Network + PerunClient *client.Client + net *p2p.Net + channels chan *PaymentChannel + rpcClient rpc.Client +} + +func NewPaymentClient( + name string, + network types.Network, + deployment backend.Deployment, + rpcUrl string, + account *wallet.Account, + key secp256k1.PrivateKey, + wallet *wallet.EphemeralWallet, + persistRestorer persistence.PersistRestorer, + wAddr wire.Address, + net *p2p.Net, + +) (*PaymentClient, error) { + backendRPCClient, err := rpc.Dial(rpcUrl) + if err != nil { + return nil, err + } + signer := backend.NewSignerInstance(address.AsParticipant(account.Address()).ToCKBAddress(network), key, network) + + ckbClient, err := ckbclient.NewClient(backendRPCClient, *signer, deployment) + if err != nil { + return nil, err + } + f := funder.NewDefaultFunder(ckbClient, deployment) + a := adjudicator.NewAdjudicator(ckbClient) + watcher, err := local.NewWatcher(a) + if err != nil { + return nil, err + } + /* + wireAcc := p2p.NewRandomAccount(rand.New(rand.NewSource(time.Now().UnixNano()))) + net, err := p2p.NewP2PBus(wireAcc) + if err != nil { + panic(errors.Wrap(err, "creating p2p net")) + } + bus := net.Bus + listener := net.Listener + + //wAddr := simple.NewAddress(account.Address().String()) + wAddr := wireAcc.Address() + */ + perunClient, err := client.New(wAddr, net.Bus, f, a, wallet, watcher) + if err != nil { + return nil, err + } + perunClient.EnablePersistence(persistRestorer) + + balanceRPC, err := rpc.Dial(rpcUrl) + if err != nil { + return nil, err + } + p := &PaymentClient{ + Name: name, + balance: big.NewInt(0), + sudtBalance: big.NewInt(0), + Account: account, + wAddr: wAddr, + Network: network, + PerunClient: perunClient, + channels: make(chan *PaymentChannel, 1), + rpcClient: balanceRPC, + net: net, + } + + //go p.PollBalances() + go perunClient.Handle(p, p) + return p, nil +} + +// WalletAddress returns the wallet address of the client. +func (p *PaymentClient) WalletAddress() gpwallet.Address { + return p.Account.Address() +} + +func (p *PaymentClient) WireAddress() wire.Address { + return p.wAddr +} + +func (p *PaymentClient) PeerID() string { + walletAddr := p.wAddr.(*p2p.Address) + return walletAddr.ID.String() +} + +func (p *PaymentClient) GetSudtBalance() *big.Int { + p.balanceMutex.Lock() + defer p.balanceMutex.Unlock() + return new(big.Int).Set(p.sudtBalance) +} + +// TODO: Remove as probably not required +/* +func (p *PaymentClient) NotifyAllBalance(ckbBal int64) string { + str := FormatBalance(new(big.Int).SetInt64(ckbBal), p.GetSudtBalance()) + return str +} +*/ + +// GetBalances retrieves the current balances of the client. +func (p *PaymentClient) GetBalances() string { + p.PollBalances() + return FormatBalance(p.balance, p.sudtBalance) +} + +// 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 { + // 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. + log.Println("OpenChannel called") + participants := []wire.Address{p.WireAddress(), peer} + p.net.Dialer.Register(peer, peerID) + + assets := make([]gpchannel.Asset, len(amounts)) + i := 0 + for a := range amounts { + assets[i] = a + i++ + } + + // We create an initial allocation which defines the starting balances. + initAlloc := gpchannel.NewAllocation(2, assets...) + log.Println(initAlloc.Assets) + for a, amount := range amounts { + switch a := a.(type) { + case *asset.Asset: + if a.IsCKBytes { + initAlloc.SetAssetBalances(a, []gpchannel.Bal{ + CKByteToShannon(big.NewFloat(amount)), // Our initial balance. + CKByteToShannon(big.NewFloat(amount)), // Peer's initial balance. + }) + } else { + intAmount := new(big.Int).SetUint64(uint64(amount)) + initAlloc.SetAssetBalances(a, []gpchannel.Bal{ + intAmount, // Our initial balance. + intAmount, // Peer's initial balance. + }) + } + default: + panic("Asset is not of type *asset.Asset") + } + + } + log.Println("Created Allocation") + + // Prepare the channel proposal by defining the channel parameters. + challengeDuration := uint64(10) // On-chain challenge duration in seconds. + proposal, err := client.NewLedgerChannelProposal( + challengeDuration, + p.Account.Address(), + initAlloc, + participants, + ) + if err != nil { + panic(err) + } + + log.Println("Created Proposal") + + // Send the proposal. + ch, err := p.PerunClient.ProposeChannel(context.TODO(), proposal) + if err != nil { + panic(err) + } + + log.Println("Sent Channel") + + // Start the on-chain event watcher. It automatically handles disputes. + p.startWatching(ch) + + log.Println("Started Watching") + + //p.Channel = newPaymentChannel(ch, assets) + return newPaymentChannel(ch, assets) +} + +// startWatching starts the dispute watcher for the specified channel. +func (p *PaymentClient) startWatching(ch *client.Channel) { + go func() { + err := ch.Watch(p) + if err != nil { + fmt.Printf("Watcher returned with error: %v", err) + } + }() +} + +func (p *PaymentClient) AcceptedChannel() *PaymentChannel { + return <-p.channels +} + +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 new file mode 100644 index 0000000..b509ac1 --- /dev/null +++ b/payment-channel-ckb/client/handle.go @@ -0,0 +1,92 @@ +package client + +import ( + "context" + "fmt" + "log" + + "perun.network/go-perun/channel" + "perun.network/go-perun/client" +) + +// HandleProposal is the callback for incoming channel proposals. +func (p *PaymentClient) HandleProposal(prop client.ChannelProposal, r *client.ProposalResponder) { + lcp, err := func() (*client.LedgerChannelProposalMsg, error) { + // Ensure that we got a ledger channel proposal. + lcp, ok := prop.(*client.LedgerChannelProposalMsg) + if !ok { + return nil, fmt.Errorf("invalid proposal type: %T", p) + } + + // Check that we have the correct number of participants. + if lcp.NumPeers() != 2 { + return nil, fmt.Errorf("invalid number of participants: %d", lcp.NumPeers()) + } + // Check that the channel has the expected assets and funding balances. + for i, assetAlloc := range lcp.FundingAgreement { + if assetAlloc[0].Cmp(assetAlloc[1]) != 0 { + return nil, fmt.Errorf("invalid funding balance for asset %d: %v", i, assetAlloc) + } + + } + return lcp, nil + }() + if err != nil { + _ = r.Reject(context.TODO(), err.Error()) + } + + // Create a channel accept message and send it. + accept := lcp.Accept( + p.WalletAddress(), // The Account we use in the channel. + client.WithRandomNonce(), // Our share of the channel nonce. + ) + ch, err := r.Accept(context.TODO(), accept) + if err != nil { + log.Printf("Error accepting channel proposal: %v", err) + return + } + + //TODO: startWatching + // Start the on-chain event watcher. It automatically handles disputes. + p.startWatching(ch) + + // Store channel. + p.channels <- newPaymentChannel(ch, lcp.InitBals.Clone().Assets) + //p.AcceptedChannel() +} + +// HandleUpdate is the callback for incoming channel updates. +func (p *PaymentClient) HandleUpdate(cur *channel.State, next client.ChannelUpdate, r *client.UpdateResponder) { + // We accept every update that increases our balance. + err := func() error { + err := channel.AssertAssetsEqual(cur.Assets, next.State.Assets) + if err != nil { + return fmt.Errorf("invalid assets: %v", err) + } + + receiverIdx := 1 - next.ActorIdx // This works because we are in a two-party channel. + for _, a := range cur.Assets { + curBal := cur.Allocation.Balance(receiverIdx, a) + nextBal := next.State.Allocation.Balance(receiverIdx, a) + if nextBal.Cmp(curBal) < 0 { + return fmt.Errorf("invalid balance: %v", nextBal) + } + } + + return nil + }() + if err != nil { + _ = r.Reject(context.TODO(), err.Error()) + } + + // Send the acceptance message. + err = r.Accept(context.TODO()) + if err != nil { + panic(err) + } +} + +// 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) +} diff --git a/payment-channel-ckb/client/util.go b/payment-channel-ckb/client/util.go new file mode 100644 index 0000000..e0d8c11 --- /dev/null +++ b/payment-channel-ckb/client/util.go @@ -0,0 +1,22 @@ +package client + +import ( + "math/big" +) + +// CKByteToShannon converts a given amount in CKByte to Shannon. +func CKByteToShannon(ckbyteAmount *big.Float) (shannonAmount *big.Int) { + shannonPerCKByte := new(big.Int).Exp(big.NewInt(10), big.NewInt(8), nil) + shannonPerCKByteFloat := new(big.Float).SetInt(shannonPerCKByte) + shannonAmountFloat := new(big.Float).Mul(ckbyteAmount, shannonPerCKByteFloat) + shannonAmount, _ = shannonAmountFloat.Int(nil) + return shannonAmount +} + +// ShannonToCKByte converts a given amount in Shannon to CKByte. +func ShannonToCKByte(shannonAmount *big.Int) *big.Float { + shannonPerCKByte := new(big.Int).Exp(big.NewInt(10), big.NewInt(8), nil) + shannonPerCKByteFloat := new(big.Float).SetInt(shannonPerCKByte) + shannonAmountFloat := new(big.Float).SetInt(shannonAmount) + return new(big.Float).Quo(shannonAmountFloat, shannonPerCKByteFloat) +} diff --git a/payment-channel-ckb/deployment/deployment.go b/payment-channel-ckb/deployment/deployment.go new file mode 100644 index 0000000..376c050 --- /dev/null +++ b/payment-channel-ckb/deployment/deployment.go @@ -0,0 +1,159 @@ +package deployment + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io" + "os" + "path" + "strings" + + "github.com/nervosnetwork/ckb-sdk-go/v2/types" + "perun.network/perun-ckb-backend/backend" +) + +const PFLSMinCapacity = 4100000032 + +type SUDTInfo struct { + Script *types.Script + CellDep *types.CellDep +} + +type Migration struct { + CellRecipes []struct { + Name string `json:"name"` + TxHash string `json:"tx_hash"` + Index uint32 `json:"index"` + OccupiedCapacity int64 `json:"occupied_capacity"` + DataHash string `json:"data_hash"` + TypeId interface{} `json:"type_id"` + } `json:"cell_recipes"` + DepGroupRecipes []interface{} `json:"dep_group_recipes"` +} + +func (m Migration) MakeDeployment(systemScripts SystemScripts, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) { + pcts := m.CellRecipes[0] + if pcts.Name != "pcts" { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("first cell recipe must be pcts") + } + pcls := m.CellRecipes[1] + if pcls.Name != "pcls" { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("second cell recipe must be pcls") + } + pfls := m.CellRecipes[2] + if pfls.Name != "pfls" { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("third cell recipe must be pfls") + } + sudtInfo, err := m.GetSUDT() + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + // NOTE: The SUDT lock-arg always contains a newline character at the end. + hexString := strings.ReplaceAll(sudtOwnerLockArg[2:], "\n", "") + hexString = strings.ReplaceAll(hexString, "\r", "") + hexString = strings.ReplaceAll(hexString, " ", "") + sudtInfo.Script.Args, err = hex.DecodeString(hexString) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("invalid sudt owner lock arg: %v", err) + } + + return backend.Deployment{ + Network: types.NetworkTest, + PCTSDep: types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(pcts.TxHash), + Index: m.CellRecipes[0].Index, + }, + DepType: types.DepTypeCode, + }, + PCLSDep: types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(pcls.TxHash), + Index: m.CellRecipes[0].Index, + }, + DepType: types.DepTypeCode, + }, + PFLSDep: types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(pfls.TxHash), + Index: m.CellRecipes[0].Index, + }, + DepType: types.DepTypeCode, + }, + PCTSCodeHash: types.HexToHash(pcts.DataHash), + PCTSHashType: types.HashTypeData1, + PCLSCodeHash: types.HexToHash(pcls.DataHash), + PCLSHashType: types.HashTypeData1, + PFLSCodeHash: types.HexToHash(pfls.DataHash), + PFLSHashType: types.HashTypeData1, + PFLSMinCapacity: PFLSMinCapacity, + DefaultLockScript: types.Script{ + CodeHash: systemScripts.Secp256k1Blake160SighashAll.ScriptID.CodeHash, + HashType: systemScripts.Secp256k1Blake160SighashAll.ScriptID.HashType, + Args: make([]byte, 32), + }, + DefaultLockScriptDep: systemScripts.Secp256k1Blake160SighashAll.CellDep, + SUDTDeps: map[types.Hash]types.CellDep{ + sudtInfo.Script.Hash(): *sudtInfo.CellDep, + }, + SUDTs: map[types.Hash]types.Script{ + sudtInfo.Script.Hash(): *sudtInfo.Script, + }, + }, *sudtInfo, nil +} + +func (m Migration) GetSUDT() (*SUDTInfo, error) { + sudt := m.CellRecipes[3] + if sudt.Name != "sudt" { + return nil, fmt.Errorf("fourth cell recipe must be sudt") + } + + sudtScript := types.Script{ + CodeHash: types.HexToHash(sudt.DataHash), + HashType: types.HashTypeData1, + Args: []byte{}, + } + sudtCellDep := types.CellDep{ + OutPoint: &types.OutPoint{ + TxHash: types.HexToHash(sudt.TxHash), + Index: sudt.Index, + }, + DepType: types.DepTypeCode, + } + return &SUDTInfo{ + Script: &sudtScript, + CellDep: &sudtCellDep, + }, nil +} + +func GetDeployment(migrationDir, systemScriptsDir, sudtOwnerLockArg string) (backend.Deployment, SUDTInfo, error) { + dir, err := os.ReadDir(migrationDir) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + if len(dir) != 1 { + return backend.Deployment{}, SUDTInfo{}, fmt.Errorf("migration dir must contain exactly one file") + } + migrationName := dir[0].Name() + migrationFile, err := os.Open(path.Join(migrationDir, migrationName)) + defer migrationFile.Close() + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + migrationData, err := io.ReadAll(migrationFile) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + var migration Migration + err = json.Unmarshal(migrationData, &migration) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + + ss, err := GetSystemScripts(systemScriptsDir) + if err != nil { + return backend.Deployment{}, SUDTInfo{}, err + } + return migration.MakeDeployment(ss, sudtOwnerLockArg) +} diff --git a/payment-channel-ckb/deployment/keys.go b/payment-channel-ckb/deployment/keys.go new file mode 100644 index 0000000..1d7d6bc --- /dev/null +++ b/payment-channel-ckb/deployment/keys.go @@ -0,0 +1,33 @@ +package deployment + +import ( + "encoding/hex" + "fmt" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "io" + "os" + "strings" +) + +func GetKey(path string) (*secp256k1.PrivateKey, error) { + keyFile, err := os.Open(path) + if err != nil { + return nil, err + } + defer keyFile.Close() + + rawBytes, err := io.ReadAll(keyFile) + if err != nil { + return nil, err + } + lines := strings.Split(string(rawBytes), "\n") + if len(lines) != 2 { + return nil, fmt.Errorf("key file must contain exactly two lines") + } + x := strings.Trim(lines[0], " \n") + xBytes, err := hex.DecodeString(x) + if err != nil { + return nil, err + } + return secp256k1.PrivKeyFromBytes(xBytes), nil +} diff --git a/payment-channel-ckb/deployment/system_scripts.go b/payment-channel-ckb/deployment/system_scripts.go new file mode 100644 index 0000000..77ee117 --- /dev/null +++ b/payment-channel-ckb/deployment/system_scripts.go @@ -0,0 +1,58 @@ +package deployment + +import ( + "encoding/json" + "io" + "os" + "path" + + "github.com/nervosnetwork/ckb-sdk-go/v2/types" +) + +type SystemScripts struct { + DAO struct { + CellDep types.CellDep `json:"cell_dep"` + ScriptID ScriptID `json:"script_id"` + } `json:"dao"` + Secp256k1Blake160MultisigAll struct { + CellDep types.CellDep `json:"cell_dep"` + ScriptID ScriptID `json:"script_id"` + } `json:"secp256k1_blake160_multisig_all"` + Secp256k1Blake160SighashAll struct { + CellDep types.CellDep `json:"cell_dep"` + ScriptID ScriptID `json:"script_id"` + } `json:"secp256k1_blake160_sighash_all"` + Secp256k1Data types.OutPoint `json:"secp256k1_data"` + TypeID struct { + ScriptID ScriptID `json:"script_id"` + } `json:"type_id"` +} + +type ScriptID struct { + CodeHash types.Hash `json:"code_hash"` + HashType types.ScriptHashType `json:"hash_type"` +} + +const systemScriptName = "default_scripts.json" + +func GetSystemScripts(systemScriptDir string) (SystemScripts, error) { + var ss SystemScripts + err := readJSON(systemScriptDir, &ss) + if err != nil { + return SystemScripts{}, err + } + return ss, nil +} + +func readJSON(systemScriptDir string, systemScripts *SystemScripts) error { + systemScriptFile, err := os.Open(path.Join(systemScriptDir, systemScriptName)) + defer func() { _ = systemScriptFile.Close() }() + if err != nil { + return err + } + systemScriptContent, err := io.ReadAll(systemScriptFile) + if err != nil { + return err + } + return json.Unmarshal(systemScriptContent, systemScripts) +} diff --git a/payment-channel-ckb/deployment/system_scripts_test.go b/payment-channel-ckb/deployment/system_scripts_test.go new file mode 100644 index 0000000..d7246a0 --- /dev/null +++ b/payment-channel-ckb/deployment/system_scripts_test.go @@ -0,0 +1,21 @@ +package deployment_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + "perun.network/perun-ckb-demo/deployment" +) + +func TestSystemScripts(t *testing.T) { + var ss deployment.SystemScripts + require.NoError(t, json.Unmarshal([]byte(systemScriptCase), &ss)) + msg, err := json.Marshal(ss) + require.NoError(t, err) + recovered := new(deployment.SystemScripts) + require.NoError(t, json.Unmarshal(msg, recovered)) + require.Equal(t, ss, *recovered) +} + +var systemScriptCase string = "{\"dao\":{\"cell_dep\":{\"dep_type\":\"code\",\"out_point\":{\"index\":\"0x2\",\"tx_hash\":\"0x297d19805fee99a53a6274a976df562d678beeff286776e1cd5ac9d8e1870780\"}},\"script_id\":{\"code_hash\":\"0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e\",\"hash_type\":\"type\"}},\"secp256k1_blake160_multisig_all\":{\"cell_dep\":{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x1\",\"tx_hash\":\"0xad69fbce31c6d8a8516789dec3cd4ddecbeb63619b4fa6cd3a7d00cdc788bf33\"}},\"script_id\":{\"code_hash\":\"0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8\",\"hash_type\":\"type\"}},\"secp256k1_blake160_sighash_all\":{\"cell_dep\":{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":\"0xad69fbce31c6d8a8516789dec3cd4ddecbeb63619b4fa6cd3a7d00cdc788bf33\"}},\"script_id\":{\"code_hash\":\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":\"type\"}},\"secp256k1_data\":{\"out_point\":{\"index\":\"0x3\",\"tx_hash\":\"0x297d19805fee99a53a6274a976df562d678beeff286776e1cd5ac9d8e1870780\"}},\"type_id\":{\"script_id\":{\"code_hash\":\"0x00000000000000000000000000000000000000000000000000545950455f4944\",\"hash_type\":\"type\"}}}" diff --git a/payment-channel-ckb/devnet/Makefile b/payment-channel-ckb/devnet/Makefile new file mode 100644 index 0000000..621fcad --- /dev/null +++ b/payment-channel-ckb/devnet/Makefile @@ -0,0 +1,2 @@ +dev: + tmuxp load ./devnet-session.yaml diff --git a/payment-channel-ckb/devnet/contracts/.assets/go-perun.png b/payment-channel-ckb/devnet/contracts/.assets/go-perun.png new file mode 100644 index 0000000..6d8787b Binary files /dev/null and b/payment-channel-ckb/devnet/contracts/.assets/go-perun.png differ diff --git a/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml b/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml new file mode 100644 index 0000000..948acce --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/.github/workflows/rust.yml @@ -0,0 +1,38 @@ +name: Rust + +on: + push: + branches: [ "dev" ] + pull_request: + branches: [ "dev" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + 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: Build contracts + run: capsule build + - name: Test contracts + run: capsule test diff --git a/payment-channel-ckb/devnet/contracts/.gitignore b/payment-channel-ckb/devnet/contracts/.gitignore new file mode 100644 index 0000000..8ce9103 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/.gitignore @@ -0,0 +1,14 @@ +# 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 new file mode 100644 index 0000000..d54baf9 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/Cargo.lock @@ -0,0 +1,842 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[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 = "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 = "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-channel" +version = "0.108.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "920f26cc48cadcaf6f7bcc3960fde9f9f355633b6361da8ef31e1e1c00fc8858" +dependencies = [ + "crossbeam-channel", +] + +[[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-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-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-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-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 = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "cpufeatures" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +dependencies = [ + "libc", +] + +[[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 = [ + "proc-macro2", + "quote", + "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 = "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 = "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", +] + +[[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 = "heapsize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" +dependencies = [ + "winapi", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[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 = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[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 = "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", + "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 = "perun-channel-lockscript" +version = "0.1.0" +dependencies = [ + "ckb-std", + "perun-common", +] + +[[package]] +name = "perun-channel-typescript" +version = "0.1.0" +dependencies = [ + "ckb-std", + "perun-common", +] + +[[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", +] + +[[package]] +name = "perun-funds-lockscript" +version = "0.1.0" +dependencies = [ + "ckb-std", + "perun-common", +] + +[[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", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[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_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[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 = "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-std-workspace-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" + +[[package]] +name = "sample-udt" +version = "0.1.0" +dependencies = [ + "ckb-std", + "perun-common", +] + +[[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 = "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.14", +] + +[[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 = "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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.14", +] + +[[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 = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[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/Cargo.toml b/payment-channel-ckb/devnet/contracts/Cargo.toml new file mode 100644 index 0000000..bd68a6e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/Cargo.toml @@ -0,0 +1,15 @@ +[workspace] +members = [ "contracts/perun-channel-lockscript" + , "contracts/perun-channel-typescript" + , "contracts/perun-funds-lockscript" + , "contracts/perun-common" + , "contracts/sample-udt" + ] +exclude = ["tests"] + +[profile.release] +overflow-checks = true +opt-level = 's' +lto = false +codegen-units = 1 +panic = 'abort' diff --git a/payment-channel-ckb/devnet/contracts/README.md b/payment-channel-ckb/devnet/contracts/README.md new file mode 100644 index 0000000..0f60dfb --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/README.md @@ -0,0 +1,45 @@ +


+ Perun +

+ +

Perun CKB Contracts

+ +

+ License: Apache 2.0 + CI status +

+ +# [Perun](https://perun.network/) CKB contracts + +This repository contains the scripts used to realize Perun channels on CKB. +There are three scripts available: + +## perun-channel-lockscript +This script is used to handle access-rights to the live Perun channel cell. +It ensures that only participants of the Perun channel in question are able to +consume the live channel cell. + +## perun-channel-typescript +This script is used to handle a Perun channel's state progression on-chain. +Basically a NFT script with extra functionality. + +## perun-funds-lockscript +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. + +Build contracts: + +``` sh +capsule build +``` + +Run tests: + +``` sh +capsule test +``` + +## perun-common +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. diff --git a/payment-channel-ckb/devnet/contracts/build/.gitkeep b/payment-channel-ckb/devnet/contracts/build/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/payment-channel-ckb/devnet/contracts/capsule.toml b/payment-channel-ckb/devnet/contracts/capsule.toml new file mode 100644 index 0000000..a6549a9 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/capsule.toml @@ -0,0 +1,27 @@ +# [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/.gitkeep b/payment-channel-ckb/devnet/contracts/contracts/.gitkeep new file mode 100644 index 0000000..e69de29 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 new file mode 100644 index 0000000..049cf5b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/Cargo.toml @@ -0,0 +1,10 @@ +[package] +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"] } 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/entry.rs new file mode 100644 index 0000000..d8ea048 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/entry.rs @@ -0,0 +1,72 @@ +// Import from `core` instead of from `std` since we are in no-std mode +use core::result::Result; + +// 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_cell_type, load_script}, + syscalls::SysError, +}; +use perun_common::{error::Error, perun_types::ChannelConstants}; + +// The perun-channel-lockscript (pcls) is used to lock access to interacting with a channel and is attached as lock script +// to the channel-cell (the cell which uses the perun-channel-type-script (pcts) as its type script). +// A channel defines two participants, each of which has their own unlock_script_hash (also defined in the ChannelConstants.params.{party_a,party_b}). +// The pcls allows a transaction to interact with the channel, if at least one input cell is present with: +// - cell's lock script hash == unlock_script_hash of party_a or +// - cell's lock script hash == unlock_script_hash of party_b +// We recommend using the secp256k1_blake160_sighash_all script as unlock script and corresponding payment args for the participants. +// +// 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 main() -> Result<(), Error> { + let script = load_script()?; + let args: Bytes = script.args().unpack(); + // return an error if args is invalid + if !args.is_empty() { + return Err(Error::PCLSWithArgs); + } + + // 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(); + + 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(), + )?; + + if !is_participant { + return Err(Error::NotParticipant); + } + + return Ok(()); +} + +/// check_is_participant checks if the current transaction is executed by a channel participant. +/// It does so by looking for an input cell with the same lock script hash as the unlock_script_hash +pub fn verify_is_participant( + unlock_script_hash_a: &[u8; 32], + unlock_script_hash_b: &[u8; 32], +) -> Result { + for i in 0.. { + // 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()), + }; + if cell_lock_script_hash[..] == unlock_script_hash_a[..] + || cell_lock_script_hash[..] == unlock_script_hash_b[..] + { + return Ok(true); + } + } + Ok(false) +} 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 new file mode 100644 index 0000000..9306fc4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-lockscript/src/main.rs @@ -0,0 +1,32 @@ +//! 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. + +#![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, + } +} 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 new file mode 100644 index 0000000..85ccd63 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/Cargo.toml @@ -0,0 +1,10 @@ +[package] +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"] } 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/entry.rs new file mode 100644 index 0000000..e581e4d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/entry.rs @@ -0,0 +1,904 @@ +// 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}; + +// Import CKB syscalls and structures +// https://docs.rs/ckb-std/ +use ckb_std::{ + ckb_constants::Source, + ckb_types::{ + bytes::Bytes, + packed::{Byte32, Script}, + prelude::*, + }, + 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, + }, + syscalls::{self, SysError}, +}; +use perun_common::{ + error::Error, + helpers::blake2b256, + perun_types::{ + Balances, ChannelConstants, ChannelParameters, ChannelState, ChannelStatus, ChannelToken, + ChannelWitness, ChannelWitnessUnion, SEC1EncodedPubKey, + }, + 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 main() -> Result<(), Error> { + let script = load_script()?; + let args: Bytes = script.args().unpack(); + + // return an error if args is empty + if args.is_empty() { + return Err(Error::NoArgs); + } + + // We verify that there is at most one channel in the GroupInputs and GroupOutputs respectively. + verify_max_one_channel()?; + debug!("verify_max_one_channel passed"); + + // The channel constants do not change during the lifetime of a channel. They are located in the + // args field of the pcts. + let channel_constants = + ChannelConstants::from_slice(&args).expect("unable to parse args as ChannelConstants"); + debug!("parsing channel constants passed"); + + // Verify that the channel parameters are compatible with the currently supported + // features of perun channels. + verify_channel_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_channel_action()?; + debug!("get_channel_action passed"); + + match channel_action { + ChannelAction::Start { new_status } => check_valid_start(&new_status, &channel_constants), + ChannelAction::Progress { + old_status, + new_status, + } => { + let channel_witness = load_witness()?; + debug!("load_witness passed"); + check_valid_progress( + &old_status, + &new_status, + &channel_witness, + &channel_constants, + ) + } + ChannelAction::Close { old_status } => { + let channel_witness = load_witness()?; + debug!("load_witness passed"); + check_valid_close(&old_status, &channel_witness, &channel_constants) + } + } +} + +pub fn check_valid_start( + new_status: &ChannelStatus, + channel_constants: &ChannelConstants, +) -> Result<(), Error> { + const FUNDER_INDEX: usize = 0; + + debug!("check_valid_start"); + + // Upon start of a channel, the channel constants are stored in the args field of the pcts output. + // We uniquely identify a channel through the combination of the channel id (hash of ChannelParameters, + // which is part of the ChannelConstants) and the "thread token". + // The thread token contains an OutPoint and the channel type script verifies, that that outpoint is + // consumed in the inputs of the transaction that starts the channel. + // This means: Once a (pcts-hash, channel-id, thread-token) tuple appears once on chain and is recognized + // as the on-chain representation of this channel by all peers, no other "copy" or "fake" of that channel + // can be created on chain, as an OutPoint can only be consumed once. + + // here, we verify that the OutPoint in the thread token is actually consumed. + verify_thread_token_integrity(&channel_constants.thread_token())?; + debug!("verify_thread_token_integrity passed"); + + // We verify that the channel id is the hash of the channel parameters. + verify_channel_id_integrity( + &new_status.state().channel_id(), + &channel_constants.params(), + )?; + debug!("verify_channel_id_integrity passed"); + + // We verify that the pcts is guarded by the pcls script specified in the channel constants + verify_valid_lock_script(channel_constants)?; + debug!("verify_valid_lock_script passed"); + + // We verify that the channel participants have different payment addresses + // For this purpose we consider a payment address to be the script hash of the lock script used for payments to that party + verify_different_payment_addresses(channel_constants)?; + debug!("verify_different_payment_addresses passed"); + + // We verify that there are no funds locked by the pfls hash of this channel in the inputs of the transaction. + // This check is not strictly necessary for the current implementation of the pfls, but it is good practice to + // verify this anyway, as there is no reason to include funds locked for any channel in the input of a transaction + // that creates a new channel besides trying some kind of attack. + verify_no_funds_in_inputs(channel_constants)?; + debug!("verify_no_funds_in_inputs passed"); + + // We verify that the state the channel starts with is valid according to the utxo-adaption of the perun protocol. + // For example, the channel must not be final and the version number must be 0. + verify_state_valid_as_start( + &new_status.state(), + channel_constants.pfls_min_capacity().unpack(), + )?; + debug!("verify_state_valid_as_start passed"); + + // Here we verify that the first party completes its funding and that itsfunds are actually locked to the pfls with correct args. + verify_funding_in_outputs( + FUNDER_INDEX, + &new_status.state().balances(), + channel_constants, + )?; + debug!("verify_funding_in_outputs passed"); + + // We check that the funded bit in the channel status is set to true, exactly if the funding is complete. + verify_funded_status(new_status, true)?; + debug!("verify_funded_status passed"); + + // We verify that the channel status is not disputed upon start. + verify_status_not_disputed(new_status)?; + debug!("verify_status_not_disputed passed"); + Ok(()) +} + +pub fn check_valid_progress( + old_status: &ChannelStatus, + new_status: &ChannelStatus, + witness: &ChannelWitness, + channel_constants: &ChannelConstants, +) -> Result<(), Error> { + debug!("check_valid_progress"); + + // At this point we know that the transaction progresses the channel. There are two different + // kinds of channel progression: Funding and Dispute. Which kind of progression is performed + // depends on the witness. + + // Some checks are common to both kinds of progression and are performed here. + // We check that both the old and the new state have the same channel id. + verify_equal_channel_id(&old_status.state(), &new_status.state())?; + debug!("verify_equal_channel_id passed"); + + // No kind of channel progression should pay out any funds locked by the pfls, so we just check + // that there are no funds locked by the pfls in the inputs of the transaction. + verify_no_funds_in_inputs(channel_constants)?; + debug!("verify_no_funds_in_inputs passed"); + // Here we verify that the cell with the PCTS in the outputs is locked by the same lock script + // as the input channel cell. + verify_channel_continues_locked()?; + debug!("verify_channel_continues_locked passed"); + + match witness.to_enum() { + ChannelWitnessUnion::Fund(_) => { + const FUNDER_INDEX: usize = 1; + debug!("ChannelWitnessUnion::Fund"); + + // The funding array in a channel status reflects how much each party has funded up to that point. + // Funding must not alter the channel's state. + verify_equal_channel_state(&old_status.state(), &new_status.state())?; + debug!("verify_equal_channel_state passed"); + + // Funding an already funded status is invalid. + verify_status_not_funded(&old_status)?; + debug!("verify_status_not_funded passed"); + + verify_funding_in_outputs( + FUNDER_INDEX, + &old_status.state().balances(), + channel_constants, + )?; + debug!("verify_funding_in_outputs passed"); + + // Funding a disputed status is invalid. This should not be able to happen anyway, but we check + // it nontheless. + verify_status_not_disputed(new_status)?; + debug!("verify_status_not_disputed passed"); + + // We check that the funded bit in the channel status is set to true, iff the funding is complete. + verify_funded_status(&new_status, false)?; + debug!("verify_funded_status passed"); + Ok(()) + } + ChannelWitnessUnion::Dispute(d) => { + debug!("ChannelWitnessUnion::Dispute"); + + // 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(), + )?; + debug!("verify_valid_state_sigs passed"); + Ok(()) + } + // Close, ForceClose and Abort may not happen as channel progression (if there is a continuing channel output). + ChannelWitnessUnion::Close(_) => Err(Error::ChannelCloseWithChannelOutput), + ChannelWitnessUnion::ForceClose(_) => Err(Error::ChannelForceCloseWithChannelOutput), + ChannelWitnessUnion::Abort(_) => Err(Error::ChannelAbortWithChannelOutput), + } +} + +pub fn check_valid_close( + old_status: &ChannelStatus, + channel_witness: &ChannelWitness, + channel_constants: &ChannelConstants, +) -> Result<(), Error> { + debug!("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 + let channel_capacity = load_cell_capacity(0, Source::GroupInput)?; + match channel_witness.to_enum() { + ChannelWitnessUnion::Abort(_) => { + const PARTY_B_INDEX: usize = 1; + + debug!("ChannelWitnessUnion::Abort"); + + // An abort can be performed at any time by a channel participant on a channel for which funding + // is not yet complete. It allows the initial party to reclaim its funds if e.g. the other party + // refuses to fund the channel. + 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. + // 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( + &old_status.state().balances().clear_index(PARTY_B_INDEX)?, + channel_capacity, + channel_constants, + true, + )?; + debug!("verify_all_payed 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(()) + } + ChannelWitnessUnion::Close(c) => { + debug!("check_valid_close: Close"); + + // A channel can be closed by either party at any time after funding is complete. + // For this the party needs to provide a final state (final bit set) and signatures + // by all peers on that state. + verify_equal_channel_id(&old_status.state(), &c.state())?; + debug!("check_valid_close: Channel id verified"); + verify_status_funded(old_status)?; + debug!("check_valid_close: Status funded verified"); + verify_state_finalized(&c.state())?; + debug!("check_valid_close: State finalized verified"); + verify_valid_state_sigs( + &c.sig_a().unpack(), + &c.sig_b().unpack(), + &c.state(), + &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( + &c.state().balances(), + channel_capacity, + channel_constants, + false, + )?; + debug!("verify_all_payed passed"); + Ok(()) + } + ChannelWitnessUnion::Fund(_) => Err(Error::ChannelFundWithoutChannelOutput), + ChannelWitnessUnion::Dispute(_) => Err(Error::ChannelDisputeWithoutChannelOutput), + } +} + +pub fn load_witness() -> Result { + debug!("load_witness"); + + let witness_args = load_witness_args(0, Source::GroupInput)?; + let witness_bytes: Bytes = witness_args + .input_type() + .to_opt() + .ok_or(Error::NoWitness)? + .unpack(); + let channel_witness = ChannelWitness::from_slice(&witness_bytes)?; + Ok(channel_witness) +} + +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() + ); + // Allow registering initial state + if !old_status.disputed().to_bool() + && old_status.state().version().unpack() == 0 + && new_state.version().unpack() == 0 + { + return Ok(()); + } + if old_status.state().version().unpack() < new_state.version().unpack() { + return Ok(()); + } + Err(Error::VersionNumberNotIncreasing) +} + +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 = blake2b256(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_state_not_finalized(state: &ChannelState) -> Result<(), Error> { + if state.is_final().to_bool() { + return Err(Error::StateIsFinal); + } + Ok(()) +} + +pub fn verify_status_funded(status: &ChannelStatus) -> Result<(), Error> { + if !status.funded().to_bool() { + return Err(Error::ChannelNotFunded); + } + 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_channel_continues_locked() -> Result<(), Error> { + let input_lock_script = load_cell_lock(0, Source::GroupInput)?; + let output_lock_script = load_cell_lock(0, Source::GroupOutput)?; + if input_lock_script.as_slice()[..] != output_lock_script.as_slice()[..] { + return Err(Error::ChannelDoesNotContinue); + } + Ok(()) +} + +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()[..] + { + return Err(Error::FundsInInputs); + } + } + Ok(()) +} + +pub fn verify_equal_channel_state( + old_state: &ChannelState, + new_state: &ChannelState, +) -> Result<(), Error> { + if old_state.as_slice()[..] == new_state.as_slice()[..] { + return Ok(()); + } + Err(Error::ChannelStateNotEqual) +} + +pub fn verify_funding_in_outputs( + idx: usize, + initial_balance: &Balances, + channel_constants: &ChannelConstants, +) -> Result<(), Error> { + let ckbytes_locked_for_sudts = initial_balance.sudts().get_locked_ckbytes(); + let to_fund = initial_balance.ckbytes().get(idx)? + ckbytes_locked_for_sudts; + if to_fund == 0 { + return Ok(()); + } + + let mut udt_sum = + vec![0u128, initial_balance.sudts().len().try_into().unwrap()].into_boxed_slice(); + + 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_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[..] + && 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(); + if script_hash_in_pfls_args[..] == expected_pcts_script_hash[..] { + capacity_sum += output.capacity().unpack(); + } else { + return Err(Error::InvalidPFLSInOutputs); + } + if output.type_().is_some() { + let (sudt_idx, amount) = get_sudt_amout( + initial_balance, + i, + &output.type_().to_opt().expect("checked above"), + )?; + udt_sum[sudt_idx] += amount; + } + } + } + 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)? { + return Err(Error::OwnFundingNotInOutputs); + } + + Ok(()) +} + +pub fn verify_funded_status(status: &ChannelStatus, is_start: bool) -> Result<(), Error> { + if !is_start { + if !status.funded().to_bool() { + return Err(Error::FundedBitStatusNotCorrect); + } + return Ok(()); + } + if status.state().balances().ckbytes().get(1)? != 0 { + if status.funded().to_bool() { + return Err(Error::FundedBitStatusNotCorrect); + } + return Ok(()); + } + if status.state().balances().sudts().len() != 0 { + if status.funded().to_bool() { + return Err(Error::FundedBitStatusNotCorrect); + } + return Ok(()); + } + if !status.funded().to_bool() { + return Err(Error::FundedBitStatusNotCorrect); + } + Ok(()) +} + +pub fn verify_status_not_funded(status: &ChannelStatus) -> Result<(), Error> { + if status.funded().to_bool() { + return Err(Error::StateIsFunded); + } + Ok(()) +} + +pub fn verify_channel_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::NonLedgerChannelsNotSupported); + } + if params.is_virtual_channel().to_bool() { + return Err(Error::VirtualChannelsNotSupported); + } + Ok(()) +} + +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()[..] { + return Err(Error::ChannelIdMismatch); + } + Ok(()) +} + +pub fn verify_channel_state_progression( + old_status: &ChannelStatus, + new_state: &ChannelState, +) -> Result<(), Error> { + verify_equal_channel_id(&old_status.state(), new_state)?; + verify_increasing_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(()) +} + +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, +) -> Result<(), Error> { + let digest = blake2b256(params.as_slice()); + if digest[..] != channel_id.unpack()[..] { + return Err(Error::InvalidChannelId); + } + Ok(()) +} + +pub fn verify_state_valid_as_start( + state: &ChannelState, + pfls_min_capacity: u64, +) -> Result<(), Error> { + if state.version().unpack() != 0 { + return Err(Error::StartWithNonZeroVersion); + } + if state.is_final().to_bool() { + return Err(Error::StartWithFinalizedState); + } + + // We verify that each participant's initial balance is at least the minimum capacity of a PFLS (or zero), + // to ensure that funding is possible for the initial balance distribution. + let balance_a = state.balances().ckbytes().get(0)?; + let balance_b = state.balances().ckbytes().get(1)?; + if balance_a < pfls_min_capacity && balance_a != 0 { + return Err(Error::BalanceBelowPFLSMinCapacity); + } + if balance_b < pfls_min_capacity && balance_b != 0 { + return Err(Error::BalanceBelowPFLSMinCapacity); + } + Ok(()) +} + +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()[..] { + return Err(Error::InvalidPCLSCodeHash); + } + if !lock_script + .hash_type() + .eq(&channel_constants.pcls_hash_type()) + { + return Err(Error::InvalidPCLSHashType); + } + + if !lock_script.args().is_empty() { + return Err(Error::PCLSWithArgs); + } + Ok(()) +} + +pub fn verify_status_not_disputed(status: &ChannelStatus) -> Result<(), Error> { + if status.disputed().to_bool() { + return Err(Error::StatusDisputed); + } + Ok(()) +} + +pub fn verify_status_disputed(status: &ChannelStatus) -> Result<(), Error> { + if !status.disputed().to_bool() { + return Err(Error::StatusNotDisputed); + } + Ok(()) +} + +pub fn verify_all_payed( + final_balance: &Balances, + channel_capacity: u64, + channel_constants: &ChannelConstants, + is_abort: bool, +) -> Result<(), Error> { + debug!("verify_all_payed"); + debug!("is_abort: {}", is_abort); + let minimum_payment_a = channel_constants + .params() + .party_a() + .payment_min_capacity() + .unpack(); + let minimum_payment_b: u64 = channel_constants + .params() + .party_b() + .payment_min_capacity() + .unpack(); + + let reimburse_a = final_balance.sudts().get_locked_ckbytes(); + let mut reimburse_b = 0u64; + if !is_abort { + reimburse_b = reimburse_a; + } + + 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 ckbytes_balance_b = final_balance.ckbytes().get(1)? + reimburse_b; + let payment_script_hash_b = channel_constants + .params() + .party_b() + .payment_script_hash() + .unpack(); + + debug!("ckbytes_balance_a: {}", ckbytes_balance_a); + debug!("ckbytes_balance_b: {}", ckbytes_balance_b); + + let mut ckbytes_outputs_a = 0; + let mut ckbytes_outputs_b = 0; + + let mut udt_outputs_a = + vec![0u128; final_balance.sudts().len().try_into().unwrap()].into_boxed_slice(); + let mut udt_outputs_b = + vec![0u128; final_balance.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_amout( + final_balance, + i, + &output.type_().to_opt().expect("checked above"), + )?; + udt_outputs_a[sudt_idx] += amount; + } + ckbytes_outputs_a += output.capacity().unpack(); + } + if output_lock_script_hash[..] == payment_script_hash_b[..] { + if output.type_().is_some() { + let (sudt_idx, amount) = get_sudt_amout( + final_balance, + i, + &output.type_().to_opt().expect("checked above"), + )?; + udt_outputs_b[sudt_idx] += amount; + } + ckbytes_outputs_b += output.capacity().unpack(); + } + } + 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. + 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); + } + + 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); + } + if !final_balance.sudts().fully_represented(1, &udt_outputs_b)? { + return Err(Error::NotAllPayed); + } + Ok(()) +} + +// TODO: We might want to verify that the capacity of the sudt output is at least the max_capacity of the SUDT asset. +// Not doing so may result in the ability to steal funds up to the +// (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( + balances: &Balances, + output_idx: usize, + type_script: &Script, +) -> Result<(usize, u128), Error> { + let mut buf = [0u8; SUDT_MIN_LEN]; + + let (sudt_idx, _) = balances.sudts().get_distribution(type_script)?; + let sudt_data = load_cell_data(output_idx, Source::Output)?; + if sudt_data.len() < SUDT_MIN_LEN { + return Err(Error::InvalidSUDTDataLength); + } + 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 new file mode 100644 index 0000000..9306fc4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-channel-typescript/src/main.rs @@ -0,0 +1,32 @@ +//! 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. + +#![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, + } +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml new file mode 100644 index 0000000..fb7ec7b --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/Cargo.toml @@ -0,0 +1,27 @@ +[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/blockchain.mol b/payment-channel-ckb/devnet/contracts/contracts/perun-common/blockchain.mol new file mode 100644 index 0000000..091441c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/blockchain.mol @@ -0,0 +1,108 @@ +/* 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 +} \ 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/contracts/perun-common/offchain_types.mol new file mode 100644 index 0000000..ba4758e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/offchain_types.mol @@ -0,0 +1,8 @@ +import blockchain; +import types; + +table OffChainParticipant { + pub_key: SEC1EncodedPubKey, + payment_script: Script, + unlock_script: Script, +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs new file mode 100644 index 0000000..c40a0e7 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/error.rs @@ -0,0 +1,115 @@ +use core::fmt::Debug; + +use ckb_std::error::SysError; +use k256::ecdsa::Error as SigError; +use molecule::error::VerificationError; + +/// Error +#[derive(Debug)] +#[repr(i8)] +pub enum Error { + // System Errors + IndexOutOfBound = 1, + ItemMissing, + LengthNotEnough, + Encoding, + // Verification Errors + TotalSizeNotMatch, + HeaderIsBroken, + UnknownItem, + OffsetsNotMatch, + FieldCountNotMatch, + + // Signature Errors + SignatureVerificationError, + + // Add customized errors here... + NoArgs, + NoWitness, + ChannelIdMismatch, + VersionNumberNotIncreasing, + StateIsFinal, + StateNotFinal, + ChannelNotFunded, + NotParticipant, + SumOfBalancesNotEqual, + OwnIndexNotFound, + ChannelDoesNotContinue, + MultipleMatchingOutputs, + FundsInInputs, + AppChannelsNotSupported, + NonLedgerChannelsNotSupported, + VirtualChannelsNotSupported, + ChannelStateNotEqual, + FundingChanged, + FundingNotInStatus, + OwnFundingNotInOutputs, + FundedBitStatusNotCorrect, + StateIsFunded, + + ChannelFundWithoutChannelOutput, + ChannelDisputeWithoutChannelOutput, + ChannelCloseWithChannelOutput, + ChannelForceCloseWithChannelOutput, + ChannelAbortWithChannelOutput, + + InvalidThreadToken, + InvalidChannelId, + StartWithNonZeroVersion, + StartWithFinalizedState, + InvalidPCLSCodeHash, + InvalidPCLSHashType, + PCLSWithArgs, + StatusDisputed, + StatusNotDisputed, + FundingNotZero, + NotAllPayed, + TimeLockNotExpired, + InvalidTimestamp, + UnableToLoadAnyChannelStatus, + InvalidSignature, + InvalidMessage, + InvalidPFLSInOutputs, + PCTSNotFound, + FoundDifferentChannel, + MoreThanOneChannel, + BalanceBelowPFLSMinCapacity, + SamePaymentAddress, + TypeScriptInPaymentOutput, + TypeScriptInPFLSOutput, + InvalidSUDT, + InvalidSUDTDataLength, + DecreasingAmount, +} + +impl From for Error { + fn from(err: SysError) -> Self { + use SysError::*; + match err { + IndexOutOfBound => Self::IndexOutOfBound, + ItemMissing => Self::ItemMissing, + LengthNotEnough(_) => Self::LengthNotEnough, + Encoding => Self::Encoding, + Unknown(err_code) => panic!("unexpected sys error {}", err_code), + } + } +} + +impl From for Error { + fn from(err: VerificationError) -> Self { + use VerificationError::*; + match err { + TotalSizeNotMatch(_, _, _) => Self::TotalSizeNotMatch, + HeaderIsBroken(_, _, _) => Self::HeaderIsBroken, + UnknownItem(_, _, _) => Self::UnknownItem, + OffsetsNotMatch(_) => Self::OffsetsNotMatch, + FieldCountNotMatch(_, _, _) => Self::FieldCountNotMatch, + } + } +} + +impl From for Error { + fn from(_: SigError) -> Self { + return Self::SignatureVerificationError; + } +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs new file mode 100644 index 0000000..e5f6e79 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/helpers.rs @@ -0,0 +1,448 @@ +use blake2b_rs::Blake2bBuilder; + +#[cfg(feature = "std")] +use { + crate::perun_types::ChannelState, ckb_types::bytes, ckb_types::packed::*, + ckb_types::prelude::*, std::vec::Vec, +}; + +#[cfg(not(feature = "std"))] +use { + ckb_standalone_types::packed::*, + ckb_standalone_types::prelude::*, + molecule::prelude::{vec, Vec}, +}; + +use crate::perun_types::{ + Balances, Bool, BoolUnion, ChannelParameters, ChannelStatus, SEC1EncodedPubKey, +}; +use crate::{ + error::Error, + perun_types::{CKByteDistribution, SUDTAllocation, SUDTBalances, SUDTDistribution}, +}; + +impl Bool { + pub fn to_bool(&self) -> bool { + match self.to_enum() { + BoolUnion::True(_) => true, + BoolUnion::False(_) => false, + } + } + pub fn from_bool(b: bool) -> Self { + if b { + return ctrue!(); + } else { + return cfalse!(); + } + } +} + +#[macro_export] +macro_rules! ctrue { + () => { + $crate::perun_types::BoolBuilder::default() + .set($crate::perun_types::BoolUnion::True( + $crate::perun_types::True::default(), + )) + .build() + }; +} +pub(crate) use ctrue; + +#[macro_export] +macro_rules! cfalse { + () => { + $crate::perun_types::BoolBuilder::default() + .set($crate::perun_types::BoolUnion::False( + $crate::perun_types::False::default(), + )) + .build() + }; +} +pub(crate) use cfalse; + +#[macro_export] +macro_rules! redeemer { + ($name:ident) => { + $crate::perun_types::ChannelWitnessBuilder::default() + .set($crate::perun_types::ChannelWitnessUnion::$name( + Default::default(), + )) + .build() + }; + ($x:expr) => { + $crate::perun_types::ChannelWitnessBuilder::default() + .set($x) + .build() + }; +} + +#[macro_export] +macro_rules! fund { + () => { + $crate::perun_types::ChannelWitnessUnion::Fund($crate::perun_types::Fund::default()) + }; +} + +#[macro_export] +macro_rules! close { + ($state:expr, $siga:expr, $sigb:expr) => { + $crate::perun_types::ChannelWitnessUnion::Close( + $crate::perun_types::Close::new_builder() + .state($state) + .sig_a($siga) + .sig_b($sigb) + .build(), + ) + }; +} + +#[macro_export] +macro_rules! dispute { + ($siga:expr, $sigb:expr) => { + $crate::perun_types::ChannelWitnessUnion::Dispute( + $crate::perun_types::Dispute::new_builder() + .sig_a($siga) + .sig_b($sigb) + .build(), + ) + }; +} + +impl SUDTDistribution { + pub fn sum(&self) -> u128 { + let a: u128 = self.nth0().unpack(); + let b: u128 = self.nth1().unpack(); + a + b + } + + pub fn equal(&self, other: &Balances) -> bool { + self.as_slice()[..] == other.as_slice()[..] + } + + pub fn get(&self, i: usize) -> Result { + match i { + 0 => Ok(self.nth0().unpack()), + 1 => Ok(self.nth1().unpack()), + _ => Err(Error::IndexOutOfBound), + } + } + + pub fn clear_index(&self, idx: usize) -> Result { + match idx { + 0 => Ok(self.clone().as_builder().nth0(0u128.pack()).build()), + 1 => Ok(self.clone().as_builder().nth1(0u128.pack()).build()), + _ => Err(Error::IndexOutOfBound), + } + } + + pub fn from_array(a: [u128; 2]) -> Self { + SUDTDistribution::new_builder() + .nth0(a[0].pack()) + .nth1(a[1].pack()) + .build() + } + + pub fn to_array(&self) -> [u128; 2] { + [self.nth0().unpack(), self.nth1().unpack()] + } +} + +impl Balances { + pub fn clear_index(&self, idx: usize) -> Result { + let ckbytes = self.ckbytes().clear_index(idx)?; + let mut sudts: Vec = Vec::new(); + for sb in self.sudts().into_iter() { + sudts.push( + sb.clone() + .as_builder() + .distribution(sb.distribution().clear_index(idx)?) + .build(), + ); + } + Ok(self + .clone() + .as_builder() + .ckbytes(ckbytes) + .sudts(SUDTAllocation::new_builder().set(sudts).build()) + .build()) + } + + pub fn zero_at_index(&self, idx: usize) -> Result { + if self.ckbytes().get(idx)? != 0u64 { + return Ok(false); + } + for sb in self.sudts().into_iter() { + if sb.distribution().get(idx)? != 0u128 { + return Ok(false); + } + } + return Ok(true); + } + + pub fn equal_at_index(&self, other: &Balances, idx: usize) -> Result { + if self.ckbytes().get(idx)? != other.ckbytes().get(idx)? { + return Ok(false); + } + if self.sudts().len() != other.sudts().len() { + return Ok(false); + } + for (i, sb) in self.sudts().into_iter().enumerate() { + let other_sb = other.sudts().get(i).ok_or(Error::IndexOutOfBound)?; + if sb.asset().as_slice() != other_sb.as_slice() { + return Ok(false); + } + if sb.distribution().get(idx)? != other_sb.distribution().get(idx)? { + return Ok(false); + } + } + return Ok(true); + } + + pub fn equal_in_sum(&self, other: &Balances) -> Result { + if self.ckbytes().sum() != other.ckbytes().sum() { + return Ok(false); + } + if self.sudts().len() != other.sudts().len() { + return Ok(false); + } + for (i, sb) in self.sudts().into_iter().enumerate() { + let other_sb = other.sudts().get(i).ok_or(Error::IndexOutOfBound)?; + if sb.asset().as_slice() != other_sb.asset().as_slice() { + return Ok(false); + } + if sb.distribution().sum() != other_sb.distribution().sum() { + return Ok(false); + } + } + return Ok(true); + } + + pub fn equal(&self, other: &Balances) -> bool { + self.as_slice()[..] == other.as_slice()[..] + } +} + +impl SUDTAllocation { + pub fn get_locked_ckbytes(&self) -> u64 { + let mut sum: u64 = 0u64; + for sudt in self.clone().into_iter() { + let min_cap: u64 = sudt.asset().max_capacity().unpack(); + sum += min_cap; + } + return sum; + } + + pub fn get_distribution(&self, sudt: &Script) -> Result<(usize, SUDTDistribution), Error> { + for (i, sb) in self.clone().into_iter().enumerate() { + if sb.asset().type_script().as_slice() == sudt.as_slice() { + return Ok((i, sb.distribution())); + } + } + return Err(Error::InvalidSUDT); + } + + pub fn fully_represented(&self, idx: usize, values: &[u128]) -> Result { + if values.len() < self.len() { + return Ok(false); + } + for (i, sb) in self.clone().into_iter().enumerate() { + let v = sb.distribution().get(idx)?; + if values[i] < v { + return Ok(false); + } + } + return Ok(true); + } +} + +impl CKByteDistribution { + pub fn sum(&self) -> u64 { + let a: u64 = self.nth0().unpack(); + let b: u64 = self.nth1().unpack(); + a + b + } + + pub fn equal(&self, other: &Balances) -> bool { + self.as_slice()[..] == other.as_slice()[..] + } + + pub fn get(&self, i: usize) -> Result { + match i { + 0 => Ok(self.nth0().unpack()), + 1 => Ok(self.nth1().unpack()), + _ => Err(Error::IndexOutOfBound), + } + } + + pub fn clear_index(&self, idx: usize) -> Result { + match idx { + 0 => Ok(self.clone().as_builder().nth0(0u64.pack()).build()), + 1 => Ok(self.clone().as_builder().nth1(0u64.pack()).build()), + _ => Err(Error::IndexOutOfBound), + } + } + + pub fn from_array(array: [u64; 2]) -> Self { + CKByteDistribution::new_builder() + .nth0(array[0].pack()) + .nth1(array[1].pack()) + .build() + } + + pub fn to_array(&self) -> [u64; 2] { + [self.nth0().unpack(), self.nth1().unpack()] + } +} + +pub fn geq_components(fst: &CKByteDistribution, snd: &CKByteDistribution) -> bool { + let a_fst: u64 = fst.nth0().unpack(); + let a_snd: u64 = snd.nth0().unpack(); + let b_fst: u64 = fst.nth1().unpack(); + let b_snd: u64 = snd.nth1().unpack(); + a_fst >= a_snd && b_fst >= b_snd +} + +pub const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + +pub fn blake2b256(data: &[u8]) -> [u8; 32] { + let mut result = [0u8; 32]; + let mut blake2b = Blake2bBuilder::new(32) + //.personal(CKB_HASH_PERSONALIZATION) + .build(); + blake2b.update(data); + blake2b.finalize(&mut result); + result +} + +impl ChannelStatus { + // mk_funded creates a new ChannelStatus with the funded flag set to true. + pub fn mk_funded(self) -> ChannelStatus { + self.clone().as_builder().funded(ctrue!()).build() + } + + #[cfg(feature = "std")] + /// mk_close_outputs creates the outputs for a close transaction according to the current + /// channel state. It does not matter whether the ChannelState in question is finalized or not. + pub fn mk_close_outputs( + self, + mk_lock_script: impl FnMut(u8) -> Script, + ) -> Vec<(CellOutput, bytes::Bytes)> { + self.state().mk_outputs(mk_lock_script) + } +} + +#[cfg(feature = "std")] +impl ChannelState { + pub fn mk_outputs( + self, + mk_lock_script: impl FnMut(u8) -> Script, + ) -> Vec<(CellOutput, bytes::Bytes)> { + return self.balances().mk_outputs(mk_lock_script, vec![0, 1]); + } +} + +#[cfg(feature = "std")] +impl Balances { + pub fn mk_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + ) -> Vec<(CellOutput, bytes::Bytes)> { + let mut ckbytes = self + .ckbytes() + .mk_outputs(&mut mk_lock_script, indices.clone()); + let mut sudts = self.sudts().mk_outputs(mk_lock_script, indices); + ckbytes.append(&mut sudts); + return ckbytes; + } +} + +#[cfg(feature = "std")] +impl CKByteDistribution { + pub fn mk_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + ) -> Vec<(CellOutput, bytes::Bytes)> { + // TODO: Outputs should contain min-capacity for script size... + indices + .iter() + .fold(vec![], |mut acc: Vec<(CellOutput, bytes::Bytes)>, index| { + let cap = self.get(index.clone() as usize).expect("invalid index"); + acc.push(( + CellOutput::new_builder() + .capacity(cap.pack()) + .lock(mk_lock_script(*index)) + .build(), + bytes::Bytes::new(), + )); + acc + }) + } +} + +#[cfg(feature = "std")] +impl SUDTAllocation { + pub fn mk_outputs( + self, + mut mk_lock_script: impl FnMut(u8) -> Script, + indices: Vec, + ) -> 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 + { + outputs.push(( + CellOutput::new_builder() + .capacity(cap.pack()) + .lock(mk_lock_script(*f)) + .build(), + bytes::Bytes::new(), + )); + } else { + outputs.push(( + CellOutput::new_builder() + .capacity(cap.pack()) + .lock(mk_lock_script(*f)) + .type_(udt_type_opt.clone()) + .build(), + bytes::Bytes::from( + balance + .distribution() + .get(*f as usize) + .expect("invalid index") + .to_le_bytes() + .to_vec(), + ), + )); + } + } + } + return outputs; + } +} + +impl ChannelParameters { + /// mk_party_pubkeys creates a vector of each participants public key in the correct order. + pub fn mk_party_pubkeys(self) -> Vec> { + vec![ + self.party_a().pub_key().to_vec(), + self.party_b().pub_key().to_vec(), + ] + } +} + +impl SEC1EncodedPubKey { + pub fn to_vec(&self) -> Vec { + self.as_bytes().to_vec() + } +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs new file mode 100644 index 0000000..39d0017 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/lib.rs @@ -0,0 +1,7 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod error; +pub mod helpers; +#[allow(clippy::all)] +pub mod perun_types; +pub mod sig; diff --git a/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs new file mode 100644 index 0000000..61fe220 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/perun_types.rs @@ -0,0 +1,6561 @@ +// Generated by Molecule 0.7.3 +#![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 molecule::prelude::*; + +#[derive(Clone)] +pub struct SEC1EncodedPubKey(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SEC1EncodedPubKey { + 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 SEC1EncodedPubKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SEC1EncodedPubKey { + 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 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()) + } +} +impl SEC1EncodedPubKey { + pub const TOTAL_SIZE: usize = 33; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 33; + 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 nth32(&self) -> Byte { + Byte::new_unchecked(self.0.slice(32..33)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> SEC1EncodedPubKeyReader<'r> { + SEC1EncodedPubKeyReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SEC1EncodedPubKey { + type Builder = SEC1EncodedPubKeyBuilder; + const NAME: &'static str = "SEC1EncodedPubKey"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SEC1EncodedPubKey(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 { + SEC1EncodedPubKeyReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SEC1EncodedPubKeyReader::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(), + self.nth32(), + ]) + } +} +#[derive(Clone, Copy)] +pub struct SEC1EncodedPubKeyReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SEC1EncodedPubKeyReader<'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 SEC1EncodedPubKeyReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SEC1EncodedPubKeyReader<'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> SEC1EncodedPubKeyReader<'r> { + pub const TOTAL_SIZE: usize = 33; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 33; + 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 nth32(&self) -> ByteReader<'r> { + ByteReader::new_unchecked(&self.as_slice()[32..33]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +impl<'r> molecule::prelude::Reader<'r> for SEC1EncodedPubKeyReader<'r> { + type Entity = SEC1EncodedPubKey; + const NAME: &'static str = "SEC1EncodedPubKeyReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SEC1EncodedPubKeyReader(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(()) + } +} +pub struct SEC1EncodedPubKeyBuilder(pub(crate) [Byte; 33]); +impl ::core::fmt::Debug for SEC1EncodedPubKeyBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for SEC1EncodedPubKeyBuilder { + fn default() -> Self { + SEC1EncodedPubKeyBuilder([ + 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(), + Byte::default(), + ]) + } +} +impl SEC1EncodedPubKeyBuilder { + pub const TOTAL_SIZE: usize = 33; + pub const ITEM_SIZE: usize = 1; + pub const ITEM_COUNT: usize = 33; + pub fn set(mut self, v: [Byte; 33]) -> 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 + } + pub fn nth32(mut self, v: Byte) -> Self { + self.0[32] = v; + self + } +} +impl molecule::prelude::Builder for SEC1EncodedPubKeyBuilder { + type Entity = SEC1EncodedPubKey; + const NAME: &'static str = "SEC1EncodedPubKeyBuilder"; + 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())?; + 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())?; + writer.write_all(self.0[32].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)); + SEC1EncodedPubKey::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct CKByteDistribution(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for CKByteDistribution { + 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 CKByteDistribution { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for CKByteDistribution { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + write!(f, "{}", self.nth0())?; + write!(f, ", {}", self.nth1())?; + write!(f, "]") + } +} +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()) + } +} +impl CKByteDistribution { + pub const TOTAL_SIZE: usize = 16; + pub const ITEM_SIZE: usize = 8; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> Uint64 { + Uint64::new_unchecked(self.0.slice(0..8)) + } + pub fn nth1(&self) -> Uint64 { + Uint64::new_unchecked(self.0.slice(8..16)) + } + pub fn as_reader<'r>(&'r self) -> CKByteDistributionReader<'r> { + CKByteDistributionReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for CKByteDistribution { + type Builder = CKByteDistributionBuilder; + const NAME: &'static str = "CKByteDistribution"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + CKByteDistribution(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 { + CKByteDistributionReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + CKByteDistributionReader::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()]) + } +} +#[derive(Clone, Copy)] +pub struct CKByteDistributionReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for CKByteDistributionReader<'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 CKByteDistributionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for CKByteDistributionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + write!(f, "{}", self.nth0())?; + write!(f, ", {}", self.nth1())?; + write!(f, "]") + } +} +impl<'r> CKByteDistributionReader<'r> { + pub const TOTAL_SIZE: usize = 16; + pub const ITEM_SIZE: usize = 8; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> Uint64Reader<'r> { + Uint64Reader::new_unchecked(&self.as_slice()[0..8]) + } + pub fn nth1(&self) -> Uint64Reader<'r> { + Uint64Reader::new_unchecked(&self.as_slice()[8..16]) + } +} +impl<'r> molecule::prelude::Reader<'r> for CKByteDistributionReader<'r> { + type Entity = CKByteDistribution; + const NAME: &'static str = "CKByteDistributionReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + CKByteDistributionReader(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(()) + } +} +pub struct CKByteDistributionBuilder(pub(crate) [Uint64; 2]); +impl ::core::fmt::Debug for CKByteDistributionBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for CKByteDistributionBuilder { + fn default() -> Self { + CKByteDistributionBuilder([Uint64::default(), Uint64::default()]) + } +} +impl CKByteDistributionBuilder { + pub const TOTAL_SIZE: usize = 16; + pub const ITEM_SIZE: usize = 8; + pub const ITEM_COUNT: usize = 2; + pub fn set(mut self, v: [Uint64; 2]) -> Self { + self.0 = v; + self + } + pub fn nth0(mut self, v: Uint64) -> Self { + self.0[0] = v; + self + } + pub fn nth1(mut self, v: Uint64) -> Self { + self.0[1] = v; + self + } +} +impl molecule::prelude::Builder for CKByteDistributionBuilder { + type Entity = CKByteDistribution; + const NAME: &'static str = "CKByteDistributionBuilder"; + 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())?; + 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)); + CKByteDistribution::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct SUDTDistribution(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SUDTDistribution { + 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 SUDTDistribution { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SUDTDistribution { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + write!(f, "{}", self.nth0())?; + write!(f, ", {}", self.nth1())?; + write!(f, "]") + } +} +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()) + } +} +impl SUDTDistribution { + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 16; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> Uint128 { + Uint128::new_unchecked(self.0.slice(0..16)) + } + pub fn nth1(&self) -> Uint128 { + Uint128::new_unchecked(self.0.slice(16..32)) + } + pub fn as_reader<'r>(&'r self) -> SUDTDistributionReader<'r> { + SUDTDistributionReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SUDTDistribution { + type Builder = SUDTDistributionBuilder; + const NAME: &'static str = "SUDTDistribution"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SUDTDistribution(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 { + SUDTDistributionReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SUDTDistributionReader::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()]) + } +} +#[derive(Clone, Copy)] +pub struct SUDTDistributionReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SUDTDistributionReader<'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 SUDTDistributionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SUDTDistributionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + write!(f, "{}", self.nth0())?; + write!(f, ", {}", self.nth1())?; + write!(f, "]") + } +} +impl<'r> SUDTDistributionReader<'r> { + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 16; + pub const ITEM_COUNT: usize = 2; + pub fn nth0(&self) -> Uint128Reader<'r> { + Uint128Reader::new_unchecked(&self.as_slice()[0..16]) + } + pub fn nth1(&self) -> Uint128Reader<'r> { + Uint128Reader::new_unchecked(&self.as_slice()[16..32]) + } +} +impl<'r> molecule::prelude::Reader<'r> for SUDTDistributionReader<'r> { + type Entity = SUDTDistribution; + const NAME: &'static str = "SUDTDistributionReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SUDTDistributionReader(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(()) + } +} +pub struct SUDTDistributionBuilder(pub(crate) [Uint128; 2]); +impl ::core::fmt::Debug for SUDTDistributionBuilder { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:?})", Self::NAME, &self.0[..]) + } +} +impl ::core::default::Default for SUDTDistributionBuilder { + fn default() -> Self { + SUDTDistributionBuilder([Uint128::default(), Uint128::default()]) + } +} +impl SUDTDistributionBuilder { + pub const TOTAL_SIZE: usize = 32; + pub const ITEM_SIZE: usize = 16; + pub const ITEM_COUNT: usize = 2; + pub fn set(mut self, v: [Uint128; 2]) -> Self { + self.0 = v; + self + } + pub fn nth0(mut self, v: Uint128) -> Self { + self.0[0] = v; + self + } + pub fn nth1(mut self, v: Uint128) -> Self { + self.0[1] = v; + self + } +} +impl molecule::prelude::Builder for SUDTDistributionBuilder { + type Entity = SUDTDistribution; + const NAME: &'static str = "SUDTDistributionBuilder"; + 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())?; + 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)); + SUDTDistribution::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct SUDTAllocation(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for SUDTAllocation { + 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 SUDTAllocation { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for SUDTAllocation { + 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 SUDTAllocation { + fn default() -> Self { + let v: Vec = vec![4, 0, 0, 0]; + SUDTAllocation::new_unchecked(v.into()) + } +} +impl SUDTAllocation { + 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) -> SUDTBalances { + 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 { + SUDTBalances::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; + SUDTBalances::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> SUDTAllocationReader<'r> { + SUDTAllocationReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for SUDTAllocation { + type Builder = SUDTAllocationBuilder; + const NAME: &'static str = "SUDTAllocation"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SUDTAllocation(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 { + SUDTAllocationReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + SUDTAllocationReader::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 SUDTAllocationReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for SUDTAllocationReader<'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 SUDTAllocationReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for SUDTAllocationReader<'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> SUDTAllocationReader<'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) -> SUDTBalancesReader<'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 { + SUDTBalancesReader::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; + SUDTBalancesReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for SUDTAllocationReader<'r> { + type Entity = SUDTAllocation; + const NAME: &'static str = "SUDTAllocationReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + SUDTAllocationReader(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]; + SUDTBalancesReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct SUDTAllocationBuilder(pub(crate) Vec); +impl SUDTAllocationBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: SUDTBalances) -> 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: SUDTBalances) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for SUDTAllocationBuilder { + type Entity = SUDTAllocation; + const NAME: &'static str = "SUDTAllocationBuilder"; + 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)); + SUDTAllocation::new_unchecked(inner.into()) + } +} +pub struct SUDTAllocationIterator(SUDTAllocation, usize, usize); +impl ::core::iter::Iterator for SUDTAllocationIterator { + type Item = SUDTBalances; + 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 SUDTAllocationIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for SUDTAllocation { + type Item = SUDTBalances; + type IntoIter = SUDTAllocationIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + SUDTAllocationIterator(self, 0, len) + } +} +impl<'r> SUDTAllocationReader<'r> { + pub fn iter<'t>(&'t self) -> SUDTAllocationReaderIterator<'t, 'r> { + SUDTAllocationReaderIterator(&self, 0, self.len()) + } +} +pub struct SUDTAllocationReaderIterator<'t, 'r>(&'t SUDTAllocationReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for SUDTAllocationReaderIterator<'t, 'r> { + type Item = SUDTBalancesReader<'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 SUDTAllocationReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 SUDTAsset { + 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, " }}") + } +} +impl ::core::default::Default for SUDTAsset { + 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()) + } +} +impl SUDTAsset { + 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 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 SUDTAsset { + type Builder = SUDTAssetBuilder; + const NAME: &'static str = "SUDTAsset"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SUDTAsset(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 { + SUDTAssetReader::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()) + } + 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()) + } +} +#[derive(Clone, Copy)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 SUDTAssetReader<'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, " }}") + } +} +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 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 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 { + SUDTAssetReader(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 && 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); + } + ScriptReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint64Reader::verify(&slice[offsets[1]..offsets[2]], 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; + self + } + pub fn max_capacity(mut self, v: Uint64) -> Self { + self.max_capacity = v; + self + } +} +impl molecule::prelude::Builder for SUDTAssetBuilder { + type Entity = SUDTAsset; + const NAME: &'static str = "SUDTAssetBuilder"; + fn expected_length(&self) -> usize { + 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<()> { + 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)); + SUDTAsset::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")?; + } + 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::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(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for SUDTBalances { + 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()) + } +} +impl SUDTBalances { + 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 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 SUDTBalances { + type Builder = SUDTBalancesBuilder; + const NAME: &'static str = "SUDTBalances"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + SUDTBalances(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 { + SUDTBalancesReader::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()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .asset(self.asset()) + .distribution(self.distribution()) + } +} +#[derive(Clone, Copy)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 SUDTBalancesReader<'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())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +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 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 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]) + } + 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..]) + } + } +} +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()) + } + 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 && 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); + } + SUDTAssetReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + SUDTDistributionReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(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 distribution(mut self, v: SUDTDistribution) -> Self { + self.distribution = v; + self + } +} +impl molecule::prelude::Builder for SUDTBalancesBuilder { + type Entity = SUDTBalances; + const NAME: &'static str = "SUDTBalancesBuilder"; + fn expected_length(&self) -> usize { + 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<()> { + 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)); + SUDTBalances::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 Balances { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "ckbytes", self.ckbytes())?; + write!(f, ", {}: {}", "sudts", self.sudts())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Balances { + 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()) + } +} +impl Balances { + 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 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; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + SUDTAllocation::new_unchecked(self.0.slice(start..end)) + } else { + SUDTAllocation::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 Balances { + type Builder = BalancesBuilder; + const NAME: &'static str = "Balances"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Balances(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 { + BalancesReader::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()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .ckbytes(self.ckbytes()) + .sudts(self.sudts()) + } +} +#[derive(Clone, Copy)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 BalancesReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "ckbytes", self.ckbytes())?; + write!(f, ", {}: {}", "sudts", self.sudts())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> BalancesReader<'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 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]) + } + pub fn sudts(&self) -> SUDTAllocationReader<'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; + SUDTAllocationReader::new_unchecked(&self.as_slice()[start..end]) + } else { + SUDTAllocationReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +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 new_unchecked(slice: &'r [u8]) -> Self { + BalancesReader(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 && 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); + } + CKByteDistributionReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + SUDTAllocationReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct BalancesBuilder { + pub(crate) ckbytes: CKByteDistribution, + pub(crate) sudts: SUDTAllocation, +} +impl BalancesBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn ckbytes(mut self, v: CKByteDistribution) -> Self { + self.ckbytes = v; + self + } + pub fn sudts(mut self, v: SUDTAllocation) -> Self { + self.sudts = v; + self + } +} +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() + } + 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(); + 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())?; + 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)); + Balances::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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 True { + fn default() -> Self { + let v: Vec = vec![0]; + True::new_unchecked(v.into()) + } +} +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)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> TrueReader<'r> { + TrueReader::new_unchecked(self.as_slice()) + } +} +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() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + TrueReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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> 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]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +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 { + TrueReader(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(()) + } +} +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()]) + } +} +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; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for TrueBuilder { + type Entity = True; + const NAME: &'static str = "TrueBuilder"; + 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)); + True::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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 False { + fn default() -> Self { + let v: Vec = vec![0]; + False::new_unchecked(v.into()) + } +} +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)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> FalseReader<'r> { + FalseReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for False { + type Builder = FalseBuilder; + const NAME: &'static str = "False"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + False(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 { + FalseReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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> 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]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +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 { + FalseReader(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(()) + } +} +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 FalseBuilder { + fn default() -> Self { + FalseBuilder([Byte::default()]) + } +} +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; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for FalseBuilder { + type Entity = False; + const NAME: &'static str = "FalseBuilder"; + 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)); + False::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 Bool { + 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 Bool { + fn default() -> Self { + let v: Vec = vec![0, 0, 0, 0, 0]; + Bool::new_unchecked(v.into()) + } +} +impl Bool { + pub const ITEMS_COUNT: usize = 2; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + 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) -> BoolReader<'r> { + BoolReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Bool { + type Builder = BoolBuilder; + const NAME: &'static str = "Bool"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Bool(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 { + BoolReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 BoolReader<'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> BoolReader<'r> { + pub const ITEMS_COUNT: usize = 2; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(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 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 { + BoolReader(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 => TrueReader::verify(inner_slice, compatible), + 1 => FalseReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[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 + } +} +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()) + } + 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()) + } +} +#[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::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) + } + } + } +} +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) + } + } + } +} +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<'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), + } + } +} +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(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + BoolUnion::True(item) => item.as_slice(), + BoolUnion::False(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + BoolUnion::True(_) => 0, + BoolUnion::False(_) => 1, + } + } + pub fn item_name(&self) -> &str { + match self { + BoolUnion::True(_) => "True", + BoolUnion::False(_) => "False", + } + } + 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(), + } + } +} +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(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + BoolUnionReader::True(_) => 0, + BoolUnionReader::False(_) => 1, + } + } + pub fn item_name(&self) -> &str { + match self { + BoolUnionReader::True(_) => "True", + BoolUnionReader::False(_) => "False", + } + } +} +#[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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for A { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for A { + 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 { + fn default() -> Self { + let v: Vec = vec![0]; + A::new_unchecked(v.into()) + } +} +impl A { + 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) -> AReader<'r> { + AReader::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) + } + 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 { + 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> ::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 { + AReader(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(()) + } +} +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[..]) + } +} +impl ::core::default::Default for ABuilder { + fn default() -> Self { + ABuilder([Byte::default()]) + } +} +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 nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for ABuilder { + type Entity = A; + const NAME: &'static str = "ABuilder"; + 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)); + A::new_unchecked(inner.into()) + } +} +#[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())) + } +} +impl ::core::fmt::Debug for B { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +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) + } +} +impl ::core::default::Default for B { + fn default() -> Self { + let v: Vec = vec![0]; + B::new_unchecked(v.into()) + } +} +impl B { + 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) -> BReader<'r> { + BReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for B { + type Builder = BBuilder; + const NAME: &'static str = "B"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + B(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 { + BReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 BReader<'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> { + 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 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 { + BReader(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(()) + } +} +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[..]) + } +} +impl ::core::default::Default for BBuilder { + fn default() -> Self { + BBuilder([Byte::default()]) + } +} +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 nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for BBuilder { + type Entity = B; + const NAME: &'static str = "BBuilder"; + 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)); + B::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 App { + 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 App { + fn default() -> Self { + let v: Vec = vec![]; + App::new_unchecked(v.into()) + } +} +impl App { + 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(Bytes::new_unchecked(self.0.clone())) + } + } + pub fn as_reader<'r>(&'r self) -> AppReader<'r> { + AppReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for App { + type Builder = AppBuilder; + const NAME: &'static str = "App"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + App(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 { + AppReader::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()) + } + 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 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 { + write!(f, "{}(None)", Self::NAME) + } + } +} +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<'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 new_unchecked(slice: &'r [u8]) -> Self { + AppReader(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(Debug, Default)] +pub struct AppBuilder(pub(crate) Option); +impl AppBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self + } +} +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 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)] +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())) + } +} +impl ::core::fmt::Debug for Participant { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Participant { + 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, " }}") + } +} +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 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 + } + } + 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) -> 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 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)) + } + 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)) + } + 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_reader<'r>(&'r self) -> ParticipantReader<'r> { + ParticipantReader::new_unchecked(self.as_slice()) + } +} +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 as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + 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(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<'r> ::core::fmt::Debug for ParticipantReader<'r> { + 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> { + 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, " }}") + } +} +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 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 && 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); + } + 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 + } + pub fn payment_min_capacity(mut self, v: Uint64) -> Self { + self.payment_min_capacity = v; + self + } + pub fn unlock_script_hash(mut self, v: Byte32) -> Self { + self.unlock_script_hash = v; + self + } + pub fn pub_key(mut self, v: SEC1EncodedPubKey) -> Self { + self.pub_key = v; + self + } +} +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.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.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())?; + 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()) + } +} +#[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 ::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 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 ::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 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 + } + } + 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 ChannelParameters { + type Builder = ChannelParametersBuilder; + const NAME: &'static str = "ChannelParameters"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelParameters(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 { + ChannelParametersReader::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()) + } + 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()) + } +} +#[derive(Clone, Copy)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 ChannelParametersReader<'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, " }}") + } +} +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]) + } + 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 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 { + ChannelParametersReader(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 && 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); + } + 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 + } + 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 ChannelParametersBuilder { + type Entity = ChannelParameters; + const NAME: &'static str = "ChannelParametersBuilder"; + 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() + } + 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())?; + 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()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 ChannelConstants { + 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)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for ChannelConstants { + 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()) + } +} +impl ChannelConstants { + 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 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 ChannelConstants { + type Builder = ChannelConstantsBuilder; + const NAME: &'static str = "ChannelConstants"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + ChannelConstants(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 { + ChannelConstantsReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + 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() + .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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 ChannelConstantsReader<'r> { + 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)?; + } + write!(f, " }}") + } +} +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 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 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 { + ChannelConstantsReader(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 && 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(()) + } +} +#[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, +} +impl ChannelConstantsBuilder { + pub const FIELD_COUNT: usize = 7; + pub fn params(mut self, v: ChannelParameters) -> Self { + self.params = v; + self + } + pub fn pfls_code_hash(mut self, v: Byte32) -> Self { + self.pfls_code_hash = v; + self + } + 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 ChannelConstantsBuilder { + type Entity = ChannelConstants; + const NAME: &'static str = "ChannelConstantsBuilder"; + 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() + } + 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(); + 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)); + ChannelConstants::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 Fund { + 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()) + } +} +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)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> FundReader<'r> { + FundReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Fund { + type Builder = FundBuilder; + const NAME: &'static str = "Fund"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Fund(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 { + FundReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 FundReader<'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> 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 raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +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 { + FundReader(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(()) + } +} +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; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for FundBuilder { + type Entity = Fund; + const NAME: &'static str = "FundBuilder"; + 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)); + Fund::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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 Abort { + fn default() -> Self { + let v: Vec = vec![0]; + Abort::new_unchecked(v.into()) + } +} +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)) + } + pub fn raw_data(&self) -> molecule::bytes::Bytes { + self.as_bytes() + } + pub fn as_reader<'r>(&'r self) -> AbortReader<'r> { + AbortReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Abort { + type Builder = AbortBuilder; + const NAME: &'static str = "Abort"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Abort(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 { + AbortReader::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()) + } + 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 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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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 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> 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]) + } + pub fn raw_data(&self) -> &'r [u8] { + self.as_slice() + } +} +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 { + AbortReader(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(()) + } +} +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 AbortBuilder { + fn default() -> Self { + AbortBuilder([Byte::default()]) + } +} +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; + self + } + pub fn nth0(mut self, v: Byte) -> Self { + self.0[0] = v; + self + } +} +impl molecule::prelude::Builder for AbortBuilder { + type Entity = Abort; + const NAME: &'static str = "AbortBuilder"; + 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)); + Abort::new_unchecked(inner.into()) + } +} +#[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 { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Dispute { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +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 ::core::default::Default for Dispute { + 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; + 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) -> 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; + 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) -> DisputeReader<'r> { + DisputeReader::new_unchecked(self.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) + } + 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 { + DisputeReader::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()) + } + 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()) + } +} +#[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() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +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<'r> ::core::fmt::Display for DisputeReader<'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())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> DisputeReader<'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 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; + 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 && 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); + } + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(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: 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()) + } +} +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)) + } + 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 && 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); + } + 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, +} +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: Vec = vec![0]; + ForceClose::new_unchecked(v.into()) + } +} +impl ForceClose { + 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(()) + } +} +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()) + } +} +#[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: Vec = vec![0, 0, 0, 0, 0]; + ChannelWitness::new_unchecked(v.into()) + } +} +impl ChannelWitness { + pub const ITEMS_COUNT: usize = 5; + 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 => Close::new_unchecked(inner).into(), + 4 => 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 = 5; + 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 => CloseReader::new_unchecked(inner).into(), + 4 => 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 => CloseReader::verify(inner_slice, compatible), + 4 => ForceCloseReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + 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(); + 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), + 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()) + } +} +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::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::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::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::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: 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: 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::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(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + ChannelWitnessUnion::Fund(_) => 0, + ChannelWitnessUnion::Abort(_) => 1, + ChannelWitnessUnion::Dispute(_) => 2, + ChannelWitnessUnion::Close(_) => 3, + ChannelWitnessUnion::ForceClose(_) => 4, + } + } + pub fn item_name(&self) -> &str { + match self { + ChannelWitnessUnion::Fund(_) => "Fund", + ChannelWitnessUnion::Abort(_) => "Abort", + ChannelWitnessUnion::Dispute(_) => "Dispute", + 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::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::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::Close(_) => 3, + ChannelWitnessUnionReader::ForceClose(_) => 4, + } + } + pub fn item_name(&self) -> &str { + match self { + ChannelWitnessUnionReader::Fund(_) => "Fund", + ChannelWitnessUnionReader::Abort(_) => "Abort", + ChannelWitnessUnionReader::Dispute(_) => "Dispute", + ChannelWitnessUnionReader::Close(_) => "Close", + ChannelWitnessUnionReader::ForceClose(_) => "ForceClose", + } + } +} +#[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: 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; + 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 && 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); + } + 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, +} +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())?; + 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: 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()) + } +} +impl ChannelStatus { + 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 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; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) 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) -> 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()) + } +} +#[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())?; + 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 = 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 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; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) 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 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 && 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); + } + ChannelStateReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BoolReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BoolReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct ChannelStatusBuilder { + pub(crate) state: ChannelState, + pub(crate) funded: Bool, + pub(crate) disputed: Bool, +} +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; + self + } + pub fn disputed(mut self, v: Bool) -> Self { + self.disputed = 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() + } + 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(); + 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())?; + 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: 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()) + } +} +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 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(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()) + } +} 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 new file mode 100644 index 0000000..3a7e905 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/src/sig.rs @@ -0,0 +1,11 @@ +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-common/types.mol b/payment-channel-ckb/devnet/contracts/contracts/perun-common/types.mol new file mode 100644 index 0000000..5fa3a5f --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-common/types.mol @@ -0,0 +1,140 @@ +import blockchain; + +/* 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-funds-lockscript/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml new file mode 100644 index 0000000..6e66cd6 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/Cargo.toml @@ -0,0 +1,10 @@ +[package] +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"] } 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/entry.rs new file mode 100644 index 0000000..1d21352 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/entry.rs @@ -0,0 +1,47 @@ +// 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 perun_common::error::Error; + +// Import CKB syscalls and structures +// https://docs.rs/ckb-std/ +use ckb_std::{ + ckb_constants::Source, + ckb_types::{bytes::Bytes, packed::Byte32, prelude::*}, + high_level::{load_cell_type_hash, load_script, load_transaction}, +}; + +// 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(); + + if args.is_empty() { + return Err(Error::NoArgs); + } + + let pcts_script_hash = Byte32::from_slice(&args)?; + + return verify_pcts_in_inputs(&pcts_script_hash.unpack()); +} + +pub fn verify_pcts_in_inputs(pcts_script_hash: &[u8; 32]) -> Result<(), Error> { + let num_inputs = load_transaction()?.raw().inputs().len(); + for i in 0..num_inputs { + match load_cell_type_hash(i, Source::Input)? { + Some(cell_type_script_hash) => { + if cell_type_script_hash[..] == pcts_script_hash[..] { + return Ok(()); + } else { + continue; + } + } + None => continue, + }; + } + Err(Error::PCTSNotFound) +} 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 new file mode 100644 index 0000000..9306fc4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/perun-funds-lockscript/src/main.rs @@ -0,0 +1,32 @@ +//! 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. + +#![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, + } +} diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml new file mode 100644 index 0000000..1d27e95 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/Cargo.toml @@ -0,0 +1,10 @@ +[package] +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"] } diff --git a/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs new file mode 100644 index 0000000..4e0c757 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/entry.rs @@ -0,0 +1,101 @@ +// Import from `core` instead of from `std` since we are in no-std mode +use core::result::Result; + +// 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}, + syscalls::SysError, +}; +use perun_common::error::Error; + + +pub fn main() -> Result<(), Error> { + let script = load_script()?; + let args: Bytes = script.args().unpack(); + + // return success if owner mode is true + if check_owner_mode(&args)? { + return Ok(()); + } + + let inputs_amount = collect_inputs_amount()?; + let outputs_amount = collect_outputs_amount()?; + + if inputs_amount < outputs_amount { + return Err(Error::DecreasingAmount); + } + + Ok(()) +} + +pub fn check_owner_mode(args: &Bytes) -> Result { + // With owner lock script extracted, we will look through each input in the + // 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, + ) { + 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); + } + } + Ok(false) +} + +const UDT_LEN: usize = 16; + +pub fn collect_inputs_amount() -> Result { + // let's loop through all input cells containing current UDTs, + // and gather the sum of all input tokens. + let mut inputs_amount: u128 = 0; + let mut buf = [0u8; UDT_LEN]; + + // u128 is 16 bytes + for i in 0.. { + let data = match load_cell_data(i, Source::GroupInput) { + Ok(data) => data, + Err(SysError::IndexOutOfBound) => break, + Err(err) => return Err(err.into()), + }; + + if data.len() != UDT_LEN { + return Err(Error::Encoding); + } + buf.copy_from_slice(&data); + inputs_amount += u128::from_le_bytes(buf); + } + Ok(inputs_amount) +} + +fn collect_outputs_amount() -> Result { + // With the sum of all input UDT tokens gathered, let's now iterate through + // output cells to grab the sum of all output UDT tokens. + let mut outputs_amount: u128 = 0; + + // u128 is 16 bytes + let mut buf = [0u8; UDT_LEN]; + for i in 0.. { + let data = match load_cell_data(i, Source::GroupOutput) { + Ok(data) => data, + Err(SysError::IndexOutOfBound) => break, + Err(err) => return Err(err.into()), + }; + + if data.len() != UDT_LEN { + return Err(Error::Encoding); + } + buf.copy_from_slice(&data); + 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 new file mode 100644 index 0000000..9306fc4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/contracts/sample-udt/src/main.rs @@ -0,0 +1,32 @@ +//! 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. + +#![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, + } +} diff --git a/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml new file mode 100644 index 0000000..899072d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/deployment/dev/deployment.toml @@ -0,0 +1,41 @@ +[[cells]] +name = "pcts" +enable_type_id = false +location = { file = "build/release/perun-channel-typescript" } + +[[cells]] +name = "pcls" +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" } + +[[cells]] +name = "sudt" +enable_type_id = false +location = { file = "build/release/sample-udt" } + +# +# # 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 = "0x4a3c88737f8d4d26031ad9a6d6448ba75f1533e2" +hash_type = "type" diff --git a/payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml b/payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml new file mode 100644 index 0000000..65968f5 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/deployment/release/deployment.toml @@ -0,0 +1,37 @@ +[[cells]] +name = "pcts" +enable_type_id = false +location = { file = "build/release/perun-channel-typescript" } + +[[cells]] +name = "pcls" +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" } + +# +# # 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 = "0x1edcdab5ec7e0f748c60815fce513ee1fe4d63ee" +# hash_type = "type" + diff --git a/payment-channel-ckb/devnet/contracts/migrations/.gitkeep b/payment-channel-ckb/devnet/contracts/migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/payment-channel-ckb/devnet/contracts/tests/Cargo.lock b/payment-channel-ckb/devnet/contracts/tests/Cargo.lock new file mode 100644 index 0000000..d7d027c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/Cargo.lock @@ -0,0 +1,1593 @@ +# 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 new file mode 100644 index 0000000..7d3dbcb --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tests" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ckb-testtool = "0.9" +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_core = { version = "0.6", features = ["getrandom"] } +ckb-std = "0.10.0" +ckb-occupied-capacity = "0.108.0" diff --git a/payment-channel-ckb/devnet/contracts/tests/src/lib.rs b/payment-channel-ckb/devnet/contracts/tests/src/lib.rs new file mode 100644 index 0000000..c58a205 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/lib.rs @@ -0,0 +1,63 @@ +use ckb_testtool::ckb_types::bytes::Bytes; +use std::env; +use std::fs; +use std::path::PathBuf; +use std::str::FromStr; + +#[cfg(test)] +mod perun; +#[cfg(test)] +mod tests; + +const TEST_ENV_VAR: &str = "CAPSULE_TEST_ENV"; + +pub enum TestEnv { + Debug, + Release, +} + +impl FromStr for TestEnv { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "debug" => Ok(TestEnv::Debug), + "release" => Ok(TestEnv::Release), + _ => Err("no match"), + } + } +} + +pub struct Loader(PathBuf); + +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, + }; + Self::with_test_env(test_env) + } +} + +impl Loader { + fn with_test_env(env: TestEnv) -> Self { + let load_prefix = match env { + 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"); + base_path.push(load_prefix); + Loader(base_path) + } + + pub fn load_binary(&self, name: &str) -> Bytes { + let mut path = self.0.clone(); + path.push(name); + fs::read(path).expect("binary").into() + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs new file mode 100644 index 0000000..6f06ec9 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/account.rs @@ -0,0 +1,41 @@ +use k256::{ecdsa::SigningKey, PublicKey}; +use rand_core::OsRng; +use std::fmt::Debug; + +pub trait Account: Debug + Clone { + fn public_key(&self) -> PublicKey; + fn name(&self) -> String; +} + +#[derive(Clone, Debug)] +pub struct TestAccount { + pub sk: SigningKey, + pub name: String, +} + +impl TestAccount { + pub fn new(sk: SigningKey, name: String) -> Self { + Self { sk, name } + } + + pub fn new_with_random_key(name: String) -> Self { + Self { + sk: SigningKey::random(&mut OsRng), + name, + } + } + + pub fn id(&self) -> &str { + &self.name + } +} + +impl Account for TestAccount { + fn public_key(&self) -> PublicKey { + PublicKey::from(self.sk.verifying_key()) + } + + fn name(&self) -> String { + self.name.clone() + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/action.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/action.rs new file mode 100644 index 0000000..71ea179 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/action.rs @@ -0,0 +1,22 @@ +/// Action is a generic channel action, that occurred in the channel. It is +/// parameterized by the type of the channel state. +pub enum Action +where + S: Applyable, +{ + Open(S), + Fund(S), + Abort(S), + Send(S), + Close(S), + ForceClose(S), +} + +/// Applyable allows to apply an action containing the same state type to its +/// current state. +pub trait Applyable +where + Self: Clone, +{ + fn apply(self, action: &Action) -> Self; +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs new file mode 100644 index 0000000..266d0da --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/channel.rs @@ -0,0 +1,374 @@ +use ckb_testtool::{ + ckb_types::{ + packed::{Header, OutPoint, RawHeader, Script}, + prelude::{Builder, Entity, Pack, Unpack}, + }, + context::Context, +}; +use k256::ecdsa::VerifyingKey; +use perun_common::{ + ctrue, + perun_types::{ChannelConstants, ChannelStatus, ChannelState}, +}; + +use crate::perun::{ + self, + test::{keys, Client}, +}; +use crate::perun::{harness, test}; +use std::cmp::PartialEq; +use std::collections::HashMap; +use std::fmt::Debug; + +use super::{test::cell::FundingCell, Account}; + +enum ActionValidity { + Valid, + Invalid, +} + +/// Channel is a Perun test channel. It handles the state of said channel +/// together with the participants, the current time and surrounding chain +/// context. +pub struct Channel<'a, S> +where + S: perun::Applyable + Debug + PartialEq, +{ + /// The active party. Actions called on the channel will be issued by this + /// party henceforth. + active_part: test::Client, + /// The id of the channel. + id: test::ChannelId, + /// The cell which represents this channel on-chain. + channel_cell: Option, + /// The current state of this channel. + channel_state: ChannelStatus, + /// The cells locking funds for this channel. + funding_cells: Vec, + /// The used Perun Channel Type Script. + pcts: Script, + /// All available parties. + parts: HashMap, + /// The surrounding chain context. + ctx: &'a mut Context, + /// The intial test harness environment supplying all Perun specific + /// contracts and functionality for deployment etc. + env: &'a harness::Env, + /// The current channel time. + current_time: u64, + /// The validity of the next action. + validity: ActionValidity, + /// The history of actions performed on this channel. + history: Vec>, + /// The currently tracked channel state as produced by the unit under test. + current_state: S, +} + +/// call_action! is a macro that calls the given action on the currently active +/// participant. It also sets the validity of the next action to `Valid`. +macro_rules! call_action { + ($self:ident, $action:ident $(, $x:expr)*$(,)*) => ( + { + println!("calling action {} on {}", stringify!($action), $self.active_part.name()); + let res = match $self.validity { + ActionValidity::Valid => $self.active_part.$action($self.ctx, $self.env, $($x),*), + ActionValidity::Invalid => { + let res = $self.active_part.$action($self.ctx, $self.env, $($x),*); + match res { + Ok(_) => Err(perun::Error::new("action should have failed")), + Err(_) => Ok(Default::default()), + } + } + }; + $self.validity = ActionValidity::Valid; + res + } +) +} + +impl<'a, S> Channel<'a, S> +where + S: Default + perun::Applyable + Debug + PartialEq, +{ + pub fn new( + context: &'a mut Context, + env: &'a perun::harness::Env, + parts: &[perun::TestAccount], + ) -> 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 active = m_parts.get(&parts[0].name()).expect("part not found"); + + Channel { + id: test::ChannelId::new(), + current_time: 0, + ctx: context, + env, + pcts: Script::default(), + channel_cell: None, + channel_state: ChannelStatus::default(), + funding_cells: Vec::new(), + active_part: active.clone(), + parts: m_parts.clone(), + validity: ActionValidity::Valid, + history: Vec::new(), + current_state: S::default(), + } + } + + /// with sets the currently active participant to the given `part`. + pub fn with(&mut self, part: &str) -> &mut Self { + self.active_part = self.parts.get(part).expect("part not found").clone(); + self + } + + /// delay the environment by the given `duration`, this makes the next + /// transaction receive a block_header with a timestamp that is `duration` + /// in the future. + pub fn delay(&mut self, duration: u64) { + self.current_time += duration; + } + + /// open a channel using the currently active participant set by `with(..)` + /// with the value given in `funding_agreement`. + pub fn open(&mut self, funding_agreement: &test::FundingAgreement) -> Result<(), perun::Error> { + let (id, or) = call_action!(self, open, funding_agreement)?; + self.id = id; + self.channel_cell = Some(or.channel_cell.clone()); + // Make sure the channel cell is linked to a header with a timestamp. + self.push_header_with_cell(or.channel_cell); + let mut fs = self.funding_cells.clone(); + fs.extend(or.funds_cells.iter().cloned()); + self.funding_cells = fs.to_vec(); + self.pcts = or.pcts; + self.channel_state = or.state; + Ok(()) + } + + fn push_header_with_cell(&mut self, cell: OutPoint) { + let header = Header::new_builder() + .raw( + RawHeader::new_builder() + .timestamp(self.current_time.pack()) + .build(), + ) + .build() + .into_view(); + self.ctx.insert_header(header.clone()); + // We will always use 0 as the `tx_index`. + self.ctx.link_cell_with_block(cell, header.hash(), 0); + } + + /// fund a channel using the currently active participant set by `with(..)` + /// with the value given in `funding_agreement`. + pub fn fund(&mut self, funding_agreement: &test::FundingAgreement) -> Result<(), perun::Error> { + // TODO: Lift this check into the type-system to make this more readable and stick to DRY. + let res = match &self.channel_cell { + Some(channel_cell) => { + call_action!( + self, + fund, + self.id, + funding_agreement, + channel_cell.clone(), + self.channel_state.clone(), + self.pcts.clone() + ) + } + None => panic!("no channel cell, invalid test setup"), + }?; + // TODO: DRY please. + self.channel_state = res.state; + self.channel_cell = Some(res.channel_cell.clone()); + self.push_header_with_cell(res.channel_cell); + let mut fs = self.funding_cells.clone(); + fs.extend(res.funds_cells.iter().cloned()); + self.funding_cells = fs.to_vec(); + Ok(()) + } + + /// send a payment using the currently active participant set by `with(..)` + /// 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) + } + + /// 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(); + let sigs = self.sigs_for_channel_state()?; + let res = match &self.channel_cell { + Some(channel_cell) => { + call_action!( + self, + dispute, + self.id, + channel_cell.clone(), + self.channel_state.clone(), + self.pcts.clone(), + sigs, + ) + } + None => panic!("no channel cell, invalid test setup"), + }?; + self.channel_cell = Some(res.channel_cell.clone()); + self.push_header_with_cell(res.channel_cell); + Ok(()) + } + + /// abort a channel using the currently active participant set by + /// `with(..)`. + pub fn abort(&mut self) -> Result<(), perun::Error> { + match &self.channel_cell { + Some(channel_cell) => { + call_action!( + self, + abort, + self.id, + self.channel_state.clone(), + channel_cell.clone(), + self.funding_cells.clone() + ) + } + None => panic!("no channel cell, invalid test setup"), + }?; + Ok(()) + } + + /// finalize finalizes the channel state in use. It has to be called for + /// before successful close actions. It bumps the version of the channel state. + 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(); + self.channel_state = status.as_builder().state(state).build(); + 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 + .clone() + .as_builder() + .state(new_state) + .build(); + self + } + + /// close a channel using the currently active participant set by + /// `with(..)`. + pub fn close(&mut self) -> Result<(), perun::Error> { + let sigs = self.sigs_for_channel_state()?; + match self.channel_cell.clone() { + Some(channel_cell) => call_action!( + self, + close, + self.id, + channel_cell, + self.funding_cells.clone(), + self.channel_state.clone(), + sigs + ), + None => panic!("no channel cell, invalid test setup"), + }?; + Ok(()) + } + + fn sigs_for_channel_state(&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.pcts.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 = ChannelConstants::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.channel_state.state())) + .collect(); + let sig_arr: [Vec; 2] = sigs?.try_into()?; + Ok(sig_arr) + } + + /// force_close a channel using the currently active participant set by + /// `with(..)`. + pub fn force_close(&mut self) -> 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. + self.ctx.insert_header(h.clone()); + match self.channel_cell.clone() { + Some(channel_cell) => call_action!( + self, + force_close, + self.id, + channel_cell, + self.funding_cells.clone(), + self.channel_state.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; + self + } + + /// invalid sets the validity of the next action to invalid. It resets to + /// valid after the next action. + pub fn invalid(&mut self) -> &mut Self { + self.validity = ActionValidity::Invalid; + self + } + + /// assert asserts that the channel is in a valid state according to all + /// actions that have been performed on it. This also includes the + /// surrounding context for this channel. + /// + /// If a channel was closed, it will also assert that all participants + /// were properly paid. + pub fn assert(&self) { + let expected_state: S = self + .history + .iter() + .fold(Default::default(), |acc, act| acc.apply(act)); + assert_eq!(expected_state, self.current_state) + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/error.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/error.rs new file mode 100644 index 0000000..6af554f --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/error.rs @@ -0,0 +1,65 @@ +use molecule::error::VerificationError; +use std::{error, fmt}; + +use ckb_testtool::ckb_error; + +#[derive(Debug)] +pub struct Error { + details: String, +} + +impl Error { + pub fn new(msg: &str) -> Error { + Error { + details: msg.to_string(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.details) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + &self.details + } +} + +impl From<&str> for Error { + fn from(err: &str) -> Error { + Error::new(err) + } +} + +impl From for Error { + fn from(err: ckb_occupied_capacity::Error) -> Error { + Error::new(&err.to_string()) + } +} + +impl From for Error { + fn from(err: ckb_error::Error) -> Error { + Error::new(&err.to_string()) + } +} + +impl From for Error { + fn from(err: k256::ecdsa::Error) -> Error { + Error::new(&err.to_string()) + } +} + +impl From for Error { + fn from(err: VerificationError) -> Error { + Error::new(&err.to_string()) + } +} + +impl From>> for Error { + fn from(vs: Vec>) -> Error { + Error::new(&format!("converting from nested vectors: {:?}", vs)) + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs new file mode 100644 index 0000000..4e288fc --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/harness.rs @@ -0,0 +1,285 @@ +use crate::perun; +use crate::Loader; +use ckb_occupied_capacity::{Capacity, IntoCapacity}; +use ckb_testtool::{ + builtin::ALWAYS_SUCCESS, + 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 super::test::ChannelId; +use super::test::FundingAgreement; +use super::test::FundingAgreementEntry; + +// 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 pfls_out_point: OutPoint, + // Auxiliary contracts. + pub always_success_out_point: OutPoint, + pub sample_udt_out_point: OutPoint, + + // Perun scripts. + pcls_script: Script, + pcts_script: Script, + pfls_script: Script, + pub pcls_script_dep: CellDep, + pub pcts_script_dep: CellDep, + pub pfls_script_dep: CellDep, + // Auxiliary scripts. + pub always_success_script: Script, + pub always_success_script_dep: CellDep, + pub sample_udt_script: Script, + pub sample_udt_script_dep: CellDep, + // Maximum amount of cycles used when verifying TXs. + pub max_cycles: u64, + pub min_capacity_no_script: Capacity, + pub min_capacity_pfls: Capacity, + pub sample_udt_max_cap: Capacity, + pub challenge_duration: u64, +} + +impl Env { + // prepare_env prepares the given context to be used for running Perun + // tests. + pub fn new( + context: &mut Context, + max_cycles: u64, + challenge_duration: u64, + ) -> Result { + // Perun contracts. + let pcls: Bytes = Loader::default().load_binary("perun-channel-lockscript"); + let pcts: Bytes = Loader::default().load_binary("perun-channel-typescript"); + let pfls: Bytes = Loader::default().load_binary("perun-funds-lockscript"); + let sample_udt: Bytes = Loader::default().load_binary("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); + // Auxiliary contracts. + let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone()); + + // Prepare scripts. + // Perun scripts. + let pcls_script = context + .build_script(&pcls_out_point, Default::default()) + .ok_or("perun-channel-lockscript")?; + let pcts_script = context + .build_script( + &pcts_out_point, + perun_types::ChannelConstants::default().as_bytes(), + ) + .ok_or("perun-channel-typescript")?; + let pfls_script = context + .build_script(&pfls_out_point, Default::default()) + .ok_or("perun-funds-lockscript")?; + let sample_udt_script = context + .build_script(&sample_udt_out_point, Default::default()) + .ok_or("sample-udt")?; + 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 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))?; + // Auxiliary scripts. + let always_success_script = context + .build_script(&always_success_out_point, Bytes::from(vec![0])) + .expect("always_success"); + let always_success_script_dep = CellDep::new_builder() + .out_point(always_success_out_point.clone()) + .build(); + + // Calculate minimum amount of capacity required for a cell using the always success script. + let tmp_output = CellOutput::new_builder() + .capacity(0u64.pack()) + .lock(always_success_script.clone()) + .build(); + let min_capacity_no_script = tmp_output.occupied_capacity(0u64.into_capacity())?; + + // Calculate minimum amount of capacity required for a cell using the PFLS script. + let tmp_output = CellOutput::new_builder() + .capacity(0u64.pack()) + .lock(pfls_script.clone()) + .build(); + let pfls_args_capacity = pcts_script.calc_script_hash().as_bytes().len() as u64; + let min_capacity_pfls = tmp_output.occupied_capacity(pfls_args_capacity.into_capacity())?; + println!("pfls code hash: {}", pfls_script.code_hash()); + 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()); + Ok(Env { + pcls_out_point, + pcts_out_point, + pfls_out_point, + always_success_out_point, + sample_udt_out_point, + pcls_script, + pcts_script, + pfls_script, + pcls_script_dep, + pcts_script_dep, + pfls_script_dep, + always_success_script, + always_success_script_dep, + sample_udt_script, + sample_udt_script_dep, + max_cycles, + min_capacity_no_script, + min_capacity_pfls, + sample_udt_max_cap, + challenge_duration, + }) + } + + 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) + .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) + .expect("perun-channel-typescript") + } + + 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) + .expect("perun-funds-lockscript") + } + + pub fn build_lock_script(&self, context: &mut Context, args: Bytes) -> Script { + let always_success_out_point = &self.always_success_out_point; + context + .build_script(always_success_out_point, args) + .expect("always_success") + } + + pub fn min_capacity_for_channel(&self, cs: ChannelStatus) -> Result { + let tmp_output = CellOutput::new_builder() + .capacity(0u64.pack()) + .lock(self.pcls_script.clone()) + .type_(Some(self.pcts_script.clone()).pack()) + .build(); + let cs_capacity = Capacity::bytes(cs.as_bytes().len())?; + let min_capacity = tmp_output.occupied_capacity(cs_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() + .capacity(self.min_capacity_no_script.pack()) + .lock(self.always_success_script.clone()) + .build(), + Bytes::default(), + ); + let packed_outpoint = OutPointBuilder::default() + .tx_hash(channel_token_outpoint.tx_hash()) + .index(channel_token_outpoint.index()) + .build(); + ( + perun_types::ChannelTokenBuilder::default() + .out_point(packed_outpoint.clone()) + .build(), + packed_outpoint, + ) + } + + /// create_funds_from_agreement creates a new cell with the funds for the given party index locked + /// by the always_success_script parameterized on the party index. + pub fn create_funds_from_agreement( + &self, + context: &mut Context, + 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()); + return Ok(funds); + } + + pub fn create_ckbytes_funds_for_index( + &self, + context: &mut Context, + party_index: u8, + required_funds: u64, + ) -> Result, perun::Error> { + // Create cell containing the required funds for this party. + let my_output = CellOutput::new_builder() + .capacity(required_funds.pack()) + // Lock cell using the correct party index. + .lock(self.build_lock_script(context, Bytes::from(vec![party_index]))) + .build(); + let cell = context.create_cell(my_output.clone(), Bytes::default()); + 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> { + let mut outs: Vec<(OutPoint, Capacity)> = Vec::new(); + for (sudt_script, capacity, amount) in required_funds { + let my_output = CellOutput::new_builder() + .capacity(capacity.pack()) + // Lock cell using the correct party index. + .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())); + 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 + } + + pub fn build_initial_channel_state( + &self, + channel_id: ChannelId, + client_index: u8, + funding_agreement: &FundingAgreement, + ) -> 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 channel_status = ChannelStatusBuilder::default() + .state(channel_state) + .funded(cfalse!()) + .disputed(cfalse!()) + .build(); + Ok(channel_status) + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs new file mode 100644 index 0000000..cbf1768 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/mod.rs @@ -0,0 +1,22 @@ +#[cfg(test)] +pub mod harness; + +mod error; +pub use error::*; + +pub mod channel; + +pub mod mutators; + +pub mod test; + +mod action; +pub use action::*; + +mod state; +pub use state::*; + +pub mod random; + +mod account; +pub use account::*; diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs new file mode 100644 index 0000000..24abb8c --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/mutators.rs @@ -0,0 +1,69 @@ +use crate::perun; +use ckb_testtool::ckb_types::prelude::{Unpack, Pack}; +use molecule::prelude::{Entity, Builder}; +use perun_common::perun_types::{ChannelState, CKByteDistribution, SUDTDistribution}; + +pub enum Direction { + AtoB, + BtoA, +} + +/// id returns a mutator that does not change the channel state. +pub fn id() -> impl Fn(&ChannelState) -> Result { + |s| Ok(s.clone()) +} + +/// 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()) +} + +/// 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 { + let (sender_index, receiver_index) = get_indices(direction); + move |s| { + let s_bumped = bump_version()(s)?; + let mut distribution = s_bumped.balances().ckbytes().to_array(); + if distribution[sender_index] < amount { + return Err(perun::Error::new("insufficient funds")); + } + distribution[sender_index] -= amount; + distribution[receiver_index] += amount; + 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 { + let (sender_index, receiver_index) = get_indices(direction); + move |s| { + let s_bumped = bump_version()(s)?; + let sudts = s_bumped.balances().sudts().clone(); + if asset_index >= sudts.len() { + return Err(perun::Error::new("asset index out of bounds")); + } + let sudt = sudts.get(asset_index).unwrap(); + let mut distribution = sudt.distribution().to_array(); + if distribution[sender_index] < amount { + return Err(perun::Error::new("insufficient funds")); + } + distribution[sender_index] -= amount; + distribution[receiver_index] += amount; + 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(); + Ok(s_bumped.clone().as_builder().balances(balances).build()) + } +} + +/// get_indices returns (sender_index, receiver_index) +fn get_indices(direction: Direction) -> (usize, usize) { + match direction { + 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/random.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/random.rs new file mode 100644 index 0000000..3351e08 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/random.rs @@ -0,0 +1,13 @@ +use rand::Rng; + +use super::TestAccount; + +pub fn nonce() -> [u8; 32] { + let mut rng = rand::thread_rng(); + let nonce: [u8; 32] = rng.gen(); + nonce +} + +pub fn account(name: &str) -> TestAccount { + TestAccount::new_with_random_key(name.to_string()) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/state.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/state.rs new file mode 100644 index 0000000..a06a364 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/state.rs @@ -0,0 +1,17 @@ +use crate::perun::{Action, Applyable}; + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct State {} + +impl Applyable for State { + fn apply(self, action: &Action) -> Self { + match action { + Action::Open(_) => self, + Action::Fund(_) => self, + Action::Abort(_) => self, + Action::Send(_) => self, + Action::Close(_) => self, + Action::ForceClose(_) => self, + } + } +} 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 new file mode 100644 index 0000000..668d262 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/cell.rs @@ -0,0 +1,74 @@ +use ckb_testtool::{ckb_types::{packed::{OutPoint, CellOutput}, prelude::{Unpack, Pack}}}; +use ckb_types::bytes; +use molecule::prelude::{Entity, Builder}; + +use super::{Asset, AssetRegister}; + + +#[derive(Debug, Clone)] + +pub enum FundingCell { + FundingCellCKBytes(FundingCellCKBytes), + FundingCellSUDT(FundingCellSUDT), +} + +#[derive(Debug, Clone)] +pub struct FundingCellCKBytes { + // Index of the party whose initial funds are contained in this cell. + pub index: u8, + // The amount of funding for the party given by index. + pub cap: u64, + // The outpoint of the cell containing the funds. + pub out_point: OutPoint, +} + +#[derive(Debug, Clone)] +pub struct FundingCellSUDT { + // Index of the party whose initial funds are contained in this cell. + pub index: u8, + // The amount of funding for the party given by index. + pub cap: u64, + // The outpoint of the cell containing the funds. + pub out_point: OutPoint, + pub asset: Asset, + pub asset_amount: u128, +} + +impl Default for FundingCell { + fn default() -> Self { + FundingCell::FundingCellCKBytes(FundingCellCKBytes { + index: 0, + cap: 0, + out_point: OutPoint::default(), + }) + } +} + +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(), + out_point, + asset: asset.clone(), + asset_amount: u128::from_le_bytes(data.to_vec().as_slice().try_into().unwrap()), + }) + } else { + FundingCell::FundingCellCKBytes(FundingCellCKBytes { + index: party_index, + cap: cell_output.capacity().unpack(), + out_point, + }) + } + +} + +impl FundingCell { + pub fn outpoint(&self) -> OutPoint { + match self { + FundingCell::FundingCellCKBytes(f) => f.out_point.clone(), + 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 new file mode 100644 index 0000000..3b0f445 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/channel_id.rs @@ -0,0 +1,38 @@ +use ckb_testtool::ckb_types::{ + packed::{Byte, Byte32, Byte32Builder}, + prelude::Builder, +}; +use rand::Rng; + +#[derive(Debug, Clone, Copy)] +pub struct ChannelId([u8; 32]); + +impl ChannelId { + pub fn new() -> Self { + ChannelId(Default::default()) + } + + pub fn new_random() -> Self { + ChannelId(rand::thread_rng().gen()) + } + + pub fn to_byte32(&self) -> Byte32 { + let mut byte32: [Byte; 32] = [0u8.into(); 32]; + let x = self.0; + let y = x.iter().map(|x| (*x).into()).collect::>(); + byte32.copy_from_slice(&y); + Byte32Builder::default().set(byte32).build() + } +} + +impl From<[u8; 32]> for ChannelId { + fn from(bytes: [u8; 32]) -> Self { + ChannelId(bytes) + } +} + +impl Default for ChannelId { + fn default() -> Self { + ChannelId([0u8; 32]) + } +} 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 new file mode 100644 index 0000000..cdc8aec --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/client.rs @@ -0,0 +1,259 @@ +use ckb_testtool::ckb_traits::CellDataProvider; + +use ckb_testtool::ckb_types::core::ScriptHashType; +use ckb_testtool::ckb_types::packed::{OutPoint, Script}; +use ckb_testtool::ckb_types::prelude::*; +use ckb_testtool::context::Context; + +use k256::ecdsa::signature::hazmat::PrehashSigner; +use perun_common::*; + +use perun_common::helpers::blake2b256; +use perun_common::perun_types::{ChannelState, ChannelStatus}; + +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::{keys, transaction}; + +use k256::ecdsa::{Signature, SigningKey}; + +use super::cell::FundingCell; +use super::ChannelId; + +#[derive(Clone, Debug)] +pub struct Client { + index: u8, + signing_key: SigningKey, + name: String, +} + +impl Client { + pub fn new(idx: u8, name: String, sk: SigningKey) -> Client { + Client { + index: idx, + name, + signing_key: sk, + } + } + + // pubkey returns the public key of the client as a SEC1 encoded byte + // array. + pub fn pubkey(&self) -> [u8; 33] { + keys::verifying_key_to_byte_array(&self.signing_key.verifying_key()) + } + + pub fn name(&self) -> String { + self.name.clone() + } + + pub fn open( + &self, + ctx: &mut Context, + env: &harness::Env, + 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)?; + // Create the channel token. + let (channel_token, channel_token_outpoint) = env.create_channel_token(ctx); + + let pcls = env.build_pcls(ctx, Default::default()); + let pcls_code_hash = pcls.code_hash(); + 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); + + let chan_params = perun_types::ChannelParametersBuilder::default() + .party_a(parties[0].clone()) + .party_b(parties[1].clone()) + .nonce(random::nonce().pack()) + .challenge_duration(env.challenge_duration.pack()) + .app(Default::default()) + .is_ledger_channel(ctrue!()) + .is_virtual_channel(cfalse!()) + .build(); + let cid_raw = blake2b256(chan_params.as_slice()); + let cid = ChannelId::from(cid_raw); + let chan_const = perun_types::ChannelConstantsBuilder::default() + .params(chan_params) + .pfls_code_hash(pfls_code_hash.clone()) + .pfls_hash_type(ScriptHashType::Data1.into()) + .pfls_min_capacity(env.min_capacity_pfls.pack()) + .pcls_code_hash(pcls_code_hash.clone()) + .pcls_hash_type(ScriptHashType::Data1.into()) + .thread_token(channel_token.clone()) + .build(); + + let pcts = env.build_pcts(ctx, chan_const.as_bytes()); + let pfls = env.build_pfls(ctx, pcts.calc_script_hash().as_bytes()); + + let args = transaction::OpenArgs { + cid, + funding_agreement: funding_agreement.clone(), + channel_token_outpoint: channel_token_outpoint.clone(), + inputs: inputs, + party_index: self.index, + pcls_script: pcls, + pcts_script: pcts, + pfls_script: pfls, + }; + let or = transaction::mk_open(ctx, env, args)?; + + let cycles = ctx.verify_tx(&or.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok((cid, or)) + } + + pub fn fund( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + funding_agreement: &test::FundingAgreement, + channel_cell: OutPoint, + channel_state: ChannelStatus, + 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 fr = transaction::mk_fund( + ctx, + env, + transaction::FundArgs { + channel_cell, + funding_agreement: funding_agreement.clone(), + party_index: self.index, + state: channel_state, + inputs, + pcts, + }, + )?; + let cycles = ctx.verify_tx(&fr.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(fr) + } + + pub fn send(&self, ctx: &mut Context, 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()))?; + Ok(Vec::from(s.to_der().as_bytes())) + } + + pub fn dispute( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + channel_cell: OutPoint, + channel_state: ChannelStatus, + pcts: Script, + sigs: [Vec; 2], + ) -> Result { + let dr = transaction::mk_dispute( + ctx, + env, + transaction::DisputeArgs { + channel_cell, + state: channel_state, + party_index: self.index, + pcts_script: pcts, + sigs, + }, + )?; + let cycles = ctx.verify_tx(&dr.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(dr) + } + + pub fn abort( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + state: ChannelStatus, + channel_cell: OutPoint, + funds: Vec, + ) -> Result { + let ar = transaction::mk_abort( + ctx, + env, + AbortArgs { + channel_cell, + funds, + state, + party_index: self.index, + }, + )?; + let cycles = ctx.verify_tx(&ar.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(ar) + } + + pub fn close( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + channel_cell: OutPoint, + funds_cells: Vec, + state: ChannelStatus, + sigs: [Vec; 2], + ) -> Result { + let cr = transaction::mk_close( + ctx, + env, + transaction::CloseArgs { + channel_cell, + funds_cells, + party_index: self.index, + state, + sigs, + }, + )?; + let cycles = ctx.verify_tx(&cr.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(cr) + } + + pub fn force_close( + &self, + ctx: &mut Context, + env: &harness::Env, + _cid: test::ChannelId, + channel_cell: OutPoint, + funds_cells: Vec, + state: ChannelStatus, + ) -> Result { + // We will pass all available headers to the force close transaction. + let hs = ctx.headers.keys().cloned().collect(); + let fcr = transaction::mk_force_close( + ctx, + env, + transaction::ForceCloseArgs { + headers: hs, + channel_cell, + party_index: self.index, + funds_cells, + state, + }, + )?; + let cycles = ctx.verify_tx(&fcr.tx, env.max_cycles)?; + println!("consumed cycles: {}", cycles); + Ok(fcr) + } +} 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 new file mode 100644 index 0000000..5723b99 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/funding_agreement.rs @@ -0,0 +1,282 @@ +use ckb_occupied_capacity::Capacity; +use ckb_testtool::ckb_types::packed::{Byte as PackedByte, Script}; +use ckb_testtool::ckb_types::prelude::*; +use ckb_testtool::context::Context; +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, +}; + +use crate::perun; + +#[derive(Debug, Clone)] +pub struct FundingAgreement { + entries: Vec, + register: AssetRegister, +} + +impl FundingAgreement { + pub fn register(&self) -> &AssetRegister { + &self.register + } + + pub fn has_udts(&self) -> bool { + self.register.len() > 0 + } + + pub fn new_with_capacities(caps: Vec<(P, u64)>) -> Self { + FundingAgreement { + entries: caps + .iter() + .enumerate() + .map(|(i, (acc, c))| FundingAgreementEntry { + ckbytes: *c, + sudts: Vec::new(), + index: i as u8, + pub_key: acc.public_key(), + }) + .collect(), + register: AssetRegister::new(), + } + } + + pub fn new_with_capacities_and_sudt( + caps: Vec<(P, u64)>, + asset: &Script, + max_cap: u64, + asset_amt: Vec<(P, u128)>, + ) -> Self { + let mut r = AssetRegister::new(); + let a = r.register_asset( + SUDTAsset::new_builder() + .type_script(asset.clone()) + .max_capacity(max_cap.pack()) + .build(), + ); + FundingAgreement { + entries: caps + .iter() + .enumerate() + .map(|(i, (acc, c))| FundingAgreementEntry { + ckbytes: *c, + sudts: vec![(a, asset_amt.get(i).unwrap().1)], + index: i as u8, + pub_key: acc.public_key(), + }) + .collect(), + register: r, + } + } + + pub fn content(&self) -> &Vec { + &self.entries + } + + pub fn mk_participants( + &self, + ctx: &mut Context, + env: &perun::harness::Env, + payment_min_capacity: Capacity, + ) -> Vec { + self.entries + .iter() + .map(|entry| { + let sec1_encoded_bytes: Vec<_> = entry + .pub_key + .to_encoded_point(true) + .as_bytes() + .iter() + .map(|b| PackedByte::new(*b)) + .collect(); + let sec1_pub_key = SEC1EncodedPubKeyBuilder::default() + .set(sec1_encoded_bytes.try_into().unwrap()) + .build(); + let unlock_script = ctx + .build_script( + &env.always_success_out_point, + // NOTE: To be able to make sure we can distinguish between the payout of + // the participants, we will pass their corresponding index as an argument. + // This will have no effect on the execution of the always_success_script, + // because it does not bother checking its arguments, but will allow us to + // assert the correct indices once a channel is concluded. + Bytes::from(vec![entry.index]), + ) + .expect("script"); + let unlock_script_hash = unlock_script.calc_script_hash(); + ParticipantBuilder::default() + // The payment script hash used to lock the funds after a channel close for + // this party. + .payment_script_hash(unlock_script_hash.clone()) + // The minimum capacity required for the payment cell to be valid. + .payment_min_capacity(payment_min_capacity.pack()) + // The unlock script hash used to identify this party. Normally this would be + // the lock args for a secp256k1 script or similar. Since we use the always + // success script, we will use the hash of said script parameterized by the + // party index. + .unlock_script_hash(unlock_script_hash.clone()) + .pub_key(sec1_pub_key) + .build() + }) + .collect() + } + + /// mk_balances creates a Balances object from the funding agreement where the given indices + /// already funded their part. + pub fn mk_balances(&self, indices: Vec) -> 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() { + if indices.iter().find(|&&i| i == fae.index).is_none() { + continue; + } + + 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(), + ); + } + + println!("mkbalances ckbytes: {:?}", ckbytes); + + Ok(Balances::new_builder() + .ckbytes( + CKByteDistribution::new_builder() + .nth0(ckbytes[0].pack()) + .nth1(ckbytes[1].pack()) + .build(), + ) + .sudts(SUDTAllocation::new_builder().set(sudt_alloc).build()) + .build()) + } + + pub fn expected_ckbytes_funding_for(&self, index: u8) -> Result { + let entry = self + .entries + .iter() + .find(|entry| entry.index == index) + .ok_or("unknown index")?; + Ok(entry.ckbytes) + } + + 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() + }) + } + + pub fn expected_sudts_funding_for( + &self, + index: u8, + ) -> Result, perun::Error> { + let entry = self + .entries + .iter() + .find(|entry| entry.index == index) + .ok_or("unknown index")?; + entry + .sudts + .iter() + .map(|(asset, amount)| { + let sudt_asset = self.register.get_sudtasset(asset).ok_or("unknown asset")?; + let sudt_script = sudt_asset.type_script(); + let sudt_capacity = Capacity::shannons(sudt_asset.max_capacity().unpack()); + Ok((sudt_script, sudt_capacity, *amount)) + }) + .collect::, perun::Error>>() + } +} + +#[derive(Debug, Clone)] +pub struct FundingAgreementEntry { + pub ckbytes: u64, + pub sudts: Vec<(Asset, u128)>, + pub index: u8, + pub pub_key: PublicKey, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Asset(pub u32); + +impl Asset { + pub fn new() -> Self { + Asset(0) + } +} + +impl Default for Asset { + fn default() -> Self { + Asset(0) + } +} + +#[derive(Debug, Clone)] +pub struct AssetRegister { + assets: Vec<(Asset, SUDTAsset)>, +} + +impl AssetRegister { + fn new() -> Self { + AssetRegister { + assets: Vec::new(), + } + } + + pub fn len(&self) -> usize { + self.assets.len() + } + + pub fn register_asset(&mut self, sudt_asset: SUDTAsset) -> Asset { + let asset = Asset(self.assets.len() as u32); + self.assets.push((asset, sudt_asset)); + return asset; + } + pub fn get_sudtasset(&self, asset: &Asset) -> Option<&SUDTAsset> { + match self.assets.get(asset.0 as usize) { + Some((_, sudt_asset)) => Some(sudt_asset), + None => None, + } + } + + pub fn get_asset(&self, sudt_asset: SUDTAsset) -> Option<&Asset> { + 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()[..]) + { + Some((asset, _)) => Some(asset), + None => None, + } + } + + pub fn get_sudtassets(&self) -> Vec { + self.assets.iter().map(|(_, a)| a.clone()).collect() + } +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/keys.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/keys.rs new file mode 100644 index 0000000..00c507d --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/keys.rs @@ -0,0 +1,11 @@ +use k256::{ecdsa::VerifyingKey, elliptic_curve::sec1::ToEncodedPoint}; + +pub fn verifying_key_to_byte_array(vk: &VerifyingKey) -> [u8; 33] { + vk.to_encoded_point(true) + .as_bytes() + .iter() + .map(|x| *x) + .collect::>() + .try_into() + .expect("public-key length 33") +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/mod.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/mod.rs new file mode 100644 index 0000000..effc4c1 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/mod.rs @@ -0,0 +1,15 @@ +#[cfg(test)] +mod client; +pub use client::*; + +mod funding_agreement; +pub use funding_agreement::*; + +mod channel_id; +pub use channel_id::*; + +pub mod keys; + +pub mod transaction; + +pub mod cell; 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 new file mode 100644 index 0000000..c454be0 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/abort.rs @@ -0,0 +1,85 @@ +use ckb_testtool::{ + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, OutPoint}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{perun_types::ChannelStatus, redeemer}; + +use crate::perun::{self, harness, test::{cell::FundingCell, transaction::common::add_cap_to_a}}; + +use super::common::{channel_witness, create_cells}; + +#[derive(Debug, Clone)] +pub struct AbortArgs { + pub channel_cell: OutPoint, + pub funds: Vec, + pub state: ChannelStatus, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct AbortResult { + pub tx: TransactionView, +} + +impl Default for AbortResult { + fn default() -> Self { + AbortResult { + tx: TransactionBuilder::default().build(), + } + } +} + +pub fn mk_abort( + ctx: &mut Context, + env: &harness::Env, + args: AbortArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.party_index); + let abort_action = redeemer!(Abort); + let witness_args = channel_witness!(abort_action); + let mut inputs = vec![ + CellInput::new_builder() + .previous_output(args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + inputs.extend(args.funds.iter().cloned().map(|op| { + CellInput::new_builder() + .previous_output(op.outpoint()) + .build() + })); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + // TODO: We are expecting the output amounts to be greater than the minimum amount necessary to + // accomodate the space required for each output cell. + let f = |idx| env.build_lock_script(ctx, Bytes::from(vec![idx])); + let channel_cap = env.min_capacity_for_channel(args.state.clone())?; + let balances = add_cap_to_a(&args.state.state().balances(), channel_cap); + let outputs = balances.mk_outputs(f, vec![0]); + let outputs_data: Vec<_> = outputs.iter().map(|o| o.1.clone()).collect(); + + let cell_deps = vec![ + env.pcls_script_dep.clone(), + env.pcts_script_dep.clone(), + env.always_success_script_dep.clone(), + ]; + + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().cloned().map(|o| o.0)) + .outputs_data(outputs_data.pack()) + .cell_deps(cell_deps) + .header_deps(headers) + .witness(witness_args.as_bytes().pack()) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(AbortResult { tx }) +} 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 new file mode 100644 index 0000000..e40f6f7 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/close.rs @@ -0,0 +1,96 @@ +use ckb_testtool::{ + ckb_types::packed::{CellInput, OutPoint}, + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{close, perun_types::ChannelStatus, redeemer}; + +use crate::perun::{ + self, harness, + test::{cell::FundingCell, transaction::common::channel_witness}, +}; + +use super::common::{create_cells, add_cap_to_a}; + +#[derive(Debug, Clone)] +pub struct CloseArgs { + /// The channel cell which tracks the channel on-chain. + pub channel_cell: OutPoint, + /// All funding cells used to initially fund the channel. + pub funds_cells: Vec, + /// The channel state which shall be used for closing. + pub state: ChannelStatus, + /// The DER encoded signatures for the channel state in proper order of parties. + pub sigs: [Vec; 2], + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct CloseResult { + pub tx: TransactionView, +} + +impl Default for CloseResult { + fn default() -> Self { + CloseResult { + tx: TransactionBuilder::default().build(), + } + } +} + +pub fn mk_close( + ctx: &mut Context, + env: &harness::Env, + args: CloseArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.party_index); + let mut inputs = vec![ + CellInput::new_builder() + .previous_output(args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + inputs.extend(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(), + ]; + let channel_cap = env.min_capacity_for_channel(args.state.clone())?; + let balances = add_cap_to_a(&args.state.state().balances(), channel_cap); + 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(); + + let close_action = redeemer!(close!( + args.state.state(), + args.sigs[0].pack(), + args.sigs[1].pack() + )); + let witness_args = channel_witness!(close_action); + + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|o| o.0.clone())) + .outputs_data(outputs_data.pack()) + .witness(witness_args.as_bytes().pack()) + .cell_deps(cell_deps) + .header_deps(headers) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs); + Ok(CloseResult { tx }) +} 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 new file mode 100644 index 0000000..3814aad --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/common.rs @@ -0,0 +1,41 @@ +use ckb_occupied_capacity::Capacity; +use ckb_testtool::{ + bytes, + ckb_types::{packed::{Byte32, CellOutput, OutPoint}, prelude::{Unpack, Pack}}, + context::Context, +}; +use molecule::prelude::{Entity, Builder}; +use perun_common::perun_types::Balances; + +use crate::perun; + +/// Build witness args containing the given action. +macro_rules! channel_witness { + ($action:expr) => { + ckb_testtool::ckb_types::packed::WitnessArgsBuilder::default() + .input_type(Some($action.as_bytes()).pack()) + .build() + }; +} +pub(crate) use channel_witness; + +pub fn create_funding_from( + available_capacity: Capacity, + wanted_capacity: Capacity, +) -> Result { + Ok(available_capacity.safe_sub(wanted_capacity)?) +} + +pub fn create_cells(ctx: &mut Context, hash: Byte32, outputs: Vec<(CellOutput, bytes::Bytes)>) { + for (i, (output, data)) in outputs.into_iter().enumerate() { + let out_point = OutPoint::new(hash.clone(), i as u32); + ctx.create_cell_with_out_point(out_point, output, data); + } +} + +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 diff --git a/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/dispute.rs b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/dispute.rs new file mode 100644 index 0000000..aa8a5e4 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/dispute.rs @@ -0,0 +1,94 @@ +use ckb_testtool::{ + ckb_types::packed::{CellInput, CellOutput, OutPoint}, + ckb_types::{ + core::{TransactionBuilder, TransactionView}, + packed::Script, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{dispute, perun_types::ChannelStatus, redeemer}; + +use crate::perun::{self, harness, test::transaction::common::channel_witness}; + +use super::common::create_cells; + +#[derive(Debug, Clone)] +pub struct DisputeArgs { + /// The channel cell which tracks the channel on-chain. + pub channel_cell: OutPoint, + /// The channel state which shall be used for closing. + pub state: ChannelStatus, + /// The DER encoded signatures for the channel state in proper order of parties. + pub sigs: [Vec; 2], + /// The Perun channel type script used for the current channel. + pub pcts_script: Script, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct DisputeResult { + pub tx: TransactionView, + pub channel_cell: OutPoint, +} + +impl Default for DisputeResult { + fn default() -> Self { + DisputeResult { + tx: TransactionBuilder::default().build(), + channel_cell: OutPoint::default(), + } + } +} + +pub fn mk_dispute( + ctx: &mut Context, + env: &harness::Env, + args: DisputeArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.party_index); + let inputs = vec![ + CellInput::new_builder() + .previous_output(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(), + ]; + + let pcls_script = env.build_pcls(ctx, Default::default()); + let capacity_for_cs = env.min_capacity_for_channel(args.state.clone())?; + let channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(pcls_script.clone()) + .type_(Some(args.pcts_script.clone()).pack()) + .build(); + let outputs = vec![(channel_cell.clone(), args.state.as_bytes())]; + let outputs_data: Vec<_> = outputs.iter().map(|e| e.1.clone()).collect(); + + let dispute_action = redeemer!(dispute!(args.sigs[0].pack(), 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(DisputeResult { + channel_cell: OutPoint::new(tx.hash(), 0), + tx, + }) +} 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 new file mode 100644 index 0000000..a767ab5 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/force_close.rs @@ -0,0 +1,94 @@ +use ckb_testtool::{ + ckb_types::packed::{CellInput, OutPoint}, + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + packed::Byte32, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{perun_types::ChannelStatus, redeemer}; + +use crate::perun::{ + self, harness, + test::{cell::FundingCell, transaction::common::channel_witness}, +}; + +use super::common::{create_cells, add_cap_to_a}; + +#[derive(Debug, Clone)] +pub struct ForceCloseArgs { + /// The channel cell which tracks the channel on-chain. + pub channel_cell: OutPoint, + /// The latest headers for the chain containing some timestamps. + pub headers: Vec, + /// All funding cells used to initially fund the channel. + pub funds_cells: Vec, + /// The channel state which shall be used for closing. + pub state: ChannelStatus, + pub party_index: u8, +} + +#[derive(Debug, Clone)] +pub struct ForceCloseResult { + pub tx: TransactionView, +} + +impl Default for ForceCloseResult { + fn default() -> Self { + ForceCloseResult { + tx: TransactionBuilder::default().build(), + } + } +} + +pub fn mk_force_close( + ctx: &mut Context, + env: &harness::Env, + args: ForceCloseArgs, +) -> Result { + let payment_input = env.create_min_cell_for_index(ctx, args.party_index); + let mut inputs = vec![ + CellInput::new_builder() + .previous_output(args.channel_cell) + .build(), + CellInput::new_builder() + .previous_output(payment_input) + .build(), + ]; + inputs.extend(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(), + ]; + + // 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 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(); + + 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.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(ForceCloseResult { tx }) +} 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 new file mode 100644 index 0000000..15bd968 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/fund.rs @@ -0,0 +1,123 @@ +use ckb_occupied_capacity::{Capacity, IntoCapacity}; +use ckb_testtool::{ + ckb_types::{ + bytes::Bytes, + core::{TransactionBuilder, TransactionView}, + packed::{CellInput, CellOutput, OutPoint, Script}, + prelude::{Builder, Entity, Pack}, + }, + context::Context, +}; +use perun_common::{fund, perun_types::ChannelStatus, redeemer}; + +use crate::perun::{ + self, harness, + test::{cell::{FundingCell, mk_funding_cell}, FundingAgreement}, +}; + +use super::common::{channel_witness, create_cells, create_funding_from}; + +#[derive(Debug, Clone)] +pub struct FundArgs { + pub channel_cell: OutPoint, + pub funding_agreement: FundingAgreement, + pub party_index: u8, + pub inputs: Vec<(OutPoint, Capacity)>, + pub pcts: Script, + pub state: ChannelStatus, +} + +#[derive(Debug, Clone)] +pub struct FundResult { + pub tx: TransactionView, + pub channel_cell: OutPoint, + pub funds_cells: Vec, + pub state: ChannelStatus, +} + +impl Default for FundResult { + fn default() -> Self { + FundResult { + tx: TransactionBuilder::default().build(), + channel_cell: OutPoint::default(), + funds_cells: vec![], + state: ChannelStatus::default(), + } + } +} + +pub fn mk_fund( + ctx: &mut Context, + env: &harness::Env, + args: FundArgs, +) -> Result { + let fund_action = redeemer!(fund!()); + let witness_args = channel_witness!(fund_action); + let wanted = args + .funding_agreement + .expected_ckbytes_funding_for(args.party_index)?; + let pfls = env.build_pfls(ctx, args.pcts.calc_script_hash().as_bytes()); + // TODO: Make sure enough funds available all cells! + + // Note: we do not really need to shrink the balances to only contain the party's balances, as balances.mk_outputs will do so anyway. + let balances = args.funding_agreement.mk_balances(vec![args.party_index])?; + let pfls = |_| pfls.clone(); + let mut outputs = balances.mk_outputs(pfls, vec![1]); + 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(), + ]; + for (outpoint, _) in args.inputs.iter() { + 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. + let updated_cs = args.state.mk_funded(); + let capacity_for_new_cs = env.min_capacity_for_channel(updated_cs.clone())?; + let pcls = env.build_pcls(ctx, Default::default()); + let new_channel_cell = CellOutput::new_builder() + .capacity(capacity_for_new_cs.pack()) + .lock(pcls.clone()) + .type_(Some(args.pcts.clone()).pack()) + .build(); + outputs.append(&mut vec![ + (new_channel_cell.clone(), updated_cs.as_bytes()), + ( + CellOutput::new_builder() + .capacity(exchange_cell.pack()) + .lock(env.build_lock_script(ctx, Bytes::from(vec![args.party_index]))) + .build(), + Bytes::new(), + ), + ]); + 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.pcls_script_dep.clone(), + env.sample_udt_script_dep.clone(), // TODO: Make this generic + ]; + let headers: Vec<_> = ctx.headers.keys().cloned().collect(); + let rtx = TransactionBuilder::default() + .inputs(inputs) + .witness(witness_args.as_bytes().pack()) + .outputs(outputs.clone().into_iter().map(|o| o.0.clone())) + .outputs_data(outputs_data.pack()) + .cell_deps(cell_deps) + .header_deps(headers) + .build(); + 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(), + 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 new file mode 100644 index 0000000..b1d6673 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/mod.rs @@ -0,0 +1,19 @@ +mod open; +pub use open::*; + +mod fund; +pub use fund::*; + +mod abort; +pub use abort::*; + +mod close; +pub use close::*; + +mod force_close; +pub use force_close::*; + +mod dispute; +pub use dispute::*; + +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 new file mode 100644 index 0000000..808cd8e --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/perun/test/transaction/open.rs @@ -0,0 +1,129 @@ +use std::vec; + +use ckb_occupied_capacity::{Capacity, IntoCapacity}; +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::ChannelStatus; + +use crate::perun::{ + self, harness, + test::{cell::{FundingCell, mk_funding_cell}, ChannelId, FundingAgreement}, +}; + +use super::common::{create_cells, create_funding_from}; + +#[derive(Clone)] +pub struct OpenArgs { + pub cid: ChannelId, + pub funding_agreement: FundingAgreement, + pub channel_token_outpoint: OutPoint, + pub inputs: Vec<(OutPoint, Capacity)>, + pub party_index: u8, + pub pcls_script: Script, + pub pcts_script: Script, + pub pfls_script: Script, +} + +pub struct OpenResult { + pub tx: TransactionView, + pub channel_cell: OutPoint, + pub funds_cells: Vec, + pub pcts: Script, + pub state: ChannelStatus, +} + +impl Default for OpenResult { + fn default() -> Self { + OpenResult { + tx: TransactionBuilder::default().build(), + channel_cell: OutPoint::default(), + funds_cells: Vec::new(), + pcts: Script::default(), + state: ChannelStatus::default(), + } + } +} + +pub fn mk_open( + ctx: &mut Context, + env: &harness::Env, + args: OpenArgs, +) -> Result { + 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() + .previous_output(outpoint.clone()) + .build(), + ); + } + let initial_cs = + env.build_initial_channel_state(args.cid, args.party_index, &args.funding_agreement)?; + let capacity_for_cs = env.min_capacity_for_channel(initial_cs.clone())?; + let channel_cell = CellOutput::new_builder() + .capacity(capacity_for_cs.pack()) + .lock(args.pcls_script.clone()) + .type_(Some(args.pcts_script.clone()).pack()) + .build(); + 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])?; + let mut outputs = balances.mk_outputs(pfls, vec![0]); + 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())?; + // 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( + vec![ + (channel_cell.clone(), initial_cs.as_bytes()), + ( + CellOutput::new_builder() + .capacity(exchange_cell_cap.pack()) + .lock(env.build_lock_script(ctx, Bytes::from(vec![args.party_index]))) + .build(), + Bytes::new(), + ), + ].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! + ]; + let rtx = TransactionBuilder::default() + .inputs(inputs) + .outputs(outputs.iter().map(|o| o.0.clone())) + .outputs_data(outputs_data.pack()) + .cell_deps(cell_deps) + .build(); + let tx = ctx.complete_tx(rtx); + create_cells(ctx, tx.hash(), outputs.clone()); + 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(), + tx, + pcts: args.pcts_script, + state: initial_cs, + }) +} diff --git a/payment-channel-ckb/devnet/contracts/tests/src/tests.rs b/payment-channel-ckb/devnet/contracts/tests/src/tests.rs new file mode 100644 index 0000000..f21be32 --- /dev/null +++ b/payment-channel-ckb/devnet/contracts/tests/src/tests.rs @@ -0,0 +1,486 @@ +use crate::perun::mutators::*; +use crate::perun::random; + +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_common::helpers::blake2b256; +use perun_common::perun_types::{Balances, Bool, ChannelState, SEC1EncodedPubKey, CKByteDistribution}; +use perun_common::sig::verify_signature; + +const MAX_CYCLES: u64 = 10 * 10_000_000; +const CHALLENGE_DURATION_MS: u64 = 10 * 1000; + +#[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 = 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 = hex::decode(pubkey_string).expect("decoding pubkey"); + let pubkey_bytes: [Byte; 33] = pubkey + .iter() + .map(|x| (*x).into()) + .collect::>() + .try_into() + .unwrap(); + 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 channel_state = ChannelState::new_builder() + .channel_id(Byte32::zero()) + .balances(balances) + .is_final(Bool::from_bool(true)) + .version(10u64.pack()) + .build(); + let msg = channel_state.as_slice(); + let msg_hash = blake2b256(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] +fn channel_test_bench() -> Result<(), perun::Error> { + let res = [ + test_funding_abort, + test_successful_funding_with_udt, + test_successful_funding_without_udt, + test_early_force_close, + test_close, + test_force_close, + test_multiple_disputes, + test_multiple_disputes_same_version, + test_multi_asset_payment, + test_multi_asset_abort, + test_multi_asset_abort_zero_sudt_balance, + test_multi_asset_force_close, + ] + .iter() + .map(|test| { + let mut context = Context::default(); + let pe = perun::harness::Env::new(&mut context, MAX_CYCLES, CHALLENGE_DURATION_MS) + .expect("preparing environment"); + test(&mut context, &pe) + }) + .collect::>(); + res.into_iter().collect() +} + +fn create_channel_test( + context: &mut Context, + env: &perun::harness::Env, + parts: &[perun::TestAccount], + test: impl Fn(&mut perun::channel::Channel) -> Result<(), perun::Error>, +) -> Result<(), perun::Error> { + let mut chan = perun::channel::Channel::new(context, env, parts); + test(&mut chan) +} + +fn test_funding_abort( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding_timeout = 10; + let funding = [ + Capacity::bytes(1000)?.as_u64(), + Capacity::bytes(1000)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.delay(funding_timeout); + + chan.with(alice).abort().expect("aborting channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_successful_funding_without_udt( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.assert(); + Ok(()) + }) +} + + +fn test_successful_funding_with_udt( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + 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(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.with(alice) + .finalize() + .close() + .expect("closing channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_force_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.with(bob).dispute().expect("invalid channel dispute"); + + chan.delay(env.challenge_duration); + + chan.with(bob).force_close().expect("force closing channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_early_force_close(context: &mut Context, env: &perun::harness::Env) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.with(bob).dispute().expect("invalid channel dispute"); + + chan.with(bob).invalid().force_close().expect("force closing channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_multiple_disputes_same_version( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.with(alice) + .valid() + .dispute() + .expect("disputing channel"); + + chan.with(bob) + .invalid() + .dispute() + .expect("disputing channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_multiple_disputes( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + let funding_agreement = test::FundingAgreement::new_with_capacities( + parts.iter().cloned().zip(funding.iter().cloned()).collect(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.with(alice) + .valid() + .dispute() + .expect("disputing channel"); + + chan.with(bob) + .valid() + .update(bump_version()) + .dispute() + .expect("disputing channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_multi_asset_payment( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + 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(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.update(pay_ckbytes(Direction::AtoB, 50)); + chan.update(pay_sudt(Direction::BtoA, 10, 0)); + + chan.with(alice).finalize().close().expect("closing channel"); + + chan.assert(); + Ok(()) + }) +} + +pub fn test_multi_asset_abort( + context: &mut Context, + 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_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(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(alice).abort().expect("aborting channel"); + + chan.assert(); + Ok(()) + }) +} + +pub fn test_multi_asset_abort_zero_sudt_balance( + context: &mut Context, + 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_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(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(alice).abort().expect("aborting channel"); + + chan.assert(); + Ok(()) + }) +} + +fn test_multi_asset_force_close( + context: &mut Context, + env: &perun::harness::Env, +) -> Result<(), perun::Error> { + let (alice, bob) = ("alice", "bob"); + let parts = [random::account(alice), random::account(bob)]; + let funding = [ + Capacity::bytes(100)?.as_u64(), + Capacity::bytes(100)?.as_u64(), + ]; + 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(), + ); + create_channel_test(context, env, &parts, |chan| { + chan.with(alice) + .open(&funding_agreement) + .expect("opening channel"); + + chan.with(bob) + .fund(&funding_agreement) + .expect("funding channel"); + + chan.update(pay_ckbytes(Direction::AtoB, 50)); + 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"); + + chan.assert(); + Ok(()) + }) +} diff --git a/payment-channel-ckb/devnet/deploy_contracts.sh b/payment-channel-ckb/devnet/deploy_contracts.sh new file mode 100755 index 0000000..b93ca2f --- /dev/null +++ b/payment-channel-ckb/devnet/deploy_contracts.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +set -eu +[ -n "${DEBUG:-}" ] && set -x || true + +ACCOUNTS_DIR="accounts" +PERUN_CONTRACTS_DIR="contracts" +SYSTEM_SCRIPTS_DIR="system_scripts" +DEVNET_DIR="$PWD" + +genesis=$(cat $ACCOUNTS_DIR/genesis-2.txt | awk '/testnet/ { count++; if (count == 2) print $2}') + +cd $PERUN_CONTRACTS_DIR + +if [ -d "migrations/dev" ]; then + rm -rf "migrations/dev" +fi + +expect << EOF +spawn capsule deploy --address $genesis --api "http://127.0.0.1:8114" --fee 1 +expect "Confirm deployment? (Yes/No)" +send "Yes\r" +expect "Password:" +send "\r" +expect eof +EOF + +# Fetch default contracts: +cd $DEVNET_DIR + +if [ -d "$SYSTEM_SCRIPTS_DIR" ]; then + rm -rf "$SYSTEM_SCRIPTS_DIR" +fi + +mkdir -p "$SYSTEM_SCRIPTS_DIR" +## jq will interpret the code_hash and tx_hash as numbers, so we need to wrap them in quotes. +## The index must also be a string value, but yaml does not support hex values as a top level block argument +## 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' \ + | jq . > "$SYSTEM_SCRIPTS_DIR/default_scripts.json" + +cd $DEVNET_DIR + +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) + +# 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 diff --git a/payment-channel-ckb/devnet/devnet-session.yaml b/payment-channel-ckb/devnet/devnet-session.yaml new file mode 100644 index 0000000..c266d19 --- /dev/null +++ b/payment-channel-ckb/devnet/devnet-session.yaml @@ -0,0 +1,26 @@ +session_name: devnet +before_script: ./setup-devnet.sh +windows: + - layout: tiled + panes: + - shell_command: + - ckb run + - shell_command: + - sleep 3.0 + - ckb miner + - shell_command: + - sleep 3.0 + - ./print_accounts.sh + - shell_command: + - sleep 6.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 diff --git a/payment-channel-ckb/devnet/fund_accounts.expect b/payment-channel-ckb/devnet/fund_accounts.expect new file mode 100644 index 0000000..2389c17 --- /dev/null +++ b/payment-channel-ckb/devnet/fund_accounts.expect @@ -0,0 +1,7 @@ +#!/usr/bin/expect -f + +spawn ./fund_accounts.sh + +expect "Password:" +send "\r" +expect eof diff --git a/payment-channel-ckb/devnet/fund_accounts.sh b/payment-channel-ckb/devnet/fund_accounts.sh new file mode 100755 index 0000000..e404831 --- /dev/null +++ b/payment-channel-ckb/devnet/fund_accounts.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +genesis=$(cat accounts/genesis-1.txt | awk '/testnet/ && !found {print $2; found=1}') +alice=$(cat accounts/alice.txt | awk '/testnet/ && !found {print $2; found=1}') +bob=$(cat accounts/bob.txt | awk '/testnet/ && !found {print $2; found=1}') + +genesis_tx_hash=$(ckb-cli wallet get-live-cells --address $genesis | awk '/tx_hash/ {print $2}') +genesis_tx_index=$(ckb-cli wallet get-live-cells --address $genesis | awk '/output_index/ && !found {print $2; found=1}') +genesis_tx_amount=$(ckb-cli wallet get-live-cells --address $genesis | awk '/capacity/ {print $3}') +FUNDINGTX="fundingtx.json" +FUNDING_AMOUNT=1000 +CHANGE_AMOUNT=$(python -c "print(\"{:.8f}\".format($genesis_tx_amount - 2.0 * 10.0 * $FUNDING_AMOUNT - 1.0))") + +add_output() { + ckb-cli tx add-output --tx-file $FUNDINGTX --to-sighash-address $1 --capacity $2 +} + +ckb-cli tx init --tx-file $FUNDINGTX + +for ((i=1; i <= 10; i++)); do + add_output $alice $FUNDING_AMOUNT +done + +for ((i=1; i <= 10; i++)); do + add_output $bob $FUNDING_AMOUNT +done + +ckb-cli tx add-output --tx-file $FUNDINGTX --to-sighash-address $genesis --capacity $CHANGE_AMOUNT +ckb-cli tx add-input --tx-file $FUNDINGTX --tx-hash $genesis_tx_hash --index $genesis_tx_index +ckb-cli tx sign-inputs --add-signatures --tx-file $FUNDINGTX --from-account $genesis +ckb-cli tx send --tx-file $FUNDINGTX +ckb-cli tx info --tx-file $FUNDINGTX +rm $FUNDINGTX diff --git a/payment-channel-ckb/devnet/print_accounts.sh b/payment-channel-ckb/devnet/print_accounts.sh new file mode 100755 index 0000000..74919c8 --- /dev/null +++ b/payment-channel-ckb/devnet/print_accounts.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for entry in ./accounts/*; do + echo $entry + account_id=$(cat $entry | awk '/lock_arg:/ { count++; print $2}') + cat $entry + echo $account_id + echo -e '\n' | ckb-cli account export --lock-arg $account_id --extended-privkey-path ${entry%.*}.pk + echo "------------------" +done + +echo "Extract SUDT owner lock-hash into own file" +cat ./accounts/genesis-2.txt | awk '/lock_hash:/ { print $2 }' > ./accounts/sudt-owner-lock-hash.txt diff --git a/payment-channel-ckb/devnet/setup-devnet.sh b/payment-channel-ckb/devnet/setup-devnet.sh new file mode 100755 index 0000000..7625586 --- /dev/null +++ b/payment-channel-ckb/devnet/setup-devnet.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +set -eu +[ -n "${DEBUG:-}" ] && set -x || true + +# This script sets up the devnet for CKB. +# Part of the setup are a miner, two accounts Alice and Bob, as well as the +# registration of two accounts governing the genesis cells. + +ACCOUNTS_DIR="accounts" +PERUN_CONTRACTS_DIR="contracts" + +if [ -d $ACCOUNTS_DIR ]; then + rm -rf $ACCOUNTS_DIR/* +fi +mkdir -p $ACCOUNTS_DIR + +if [ -d "data" ]; then + rm -rf "data" +fi + +if [ -d "specs" ]; then + rm -rf "specs" +fi + +if [ -f "ckb-miner.toml" ]; then + rm "ckb-miner.toml" +fi + +if [ -f "ckb.toml" ]; then + rm "ckb.toml" +fi + +if [ -f "default.db-options" ]; then + rm "default.db-options" +fi + +# Build all required contracts for Perun. +DEVNET=$(pwd) +cd $PERUN_CONTRACTS_DIR +capsule build --release +# If debug contracts are wanted: +# capsule build +cd $DEVNET + +# Genesis cell #1 +GenCellOnePK="0xd00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc" +GenCellOneLockArg="0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +GenCellOneAddress="ckt1qyqvsv5240xeh85wvnau2eky8pwrhh4jr8ts8vyj37" +# Genesis cell #2 +GenCellTwoPK="0x63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d" +GenCellTwoLockArg="0x470dcdc5e44064909650113a274b3b36aecb6dc7" +GenCellTwoAddress="ckt1qyqywrwdchjyqeysjegpzw38fvandtktdhrs0zaxl4" + +create_account() { + echo -e '\n\n' | ckb-cli account new > $ACCOUNTS_DIR/$1.txt +} + +# Create accounts for genesis cells. +touch privateKeyGenesisCells.txt +echo $GenCellOnePK > privateKeyGenesisCells.txt +echo -e '\n\n' | ckb-cli account import --privkey-path privateKeyGenesisCells.txt || true +ckb-cli account list | grep -B 5 -A 4 "$GenCellOneAddress" > $ACCOUNTS_DIR/genesis-1.txt +echo $GenCellTwoPK > privateKeyGenesisCells.txt +echo -e '\n\n' | ckb-cli account import --privkey-path privateKeyGenesisCells.txt || true +ckb-cli account list | grep -B 5 -A 4 "$GenCellTwoAddress" > $ACCOUNTS_DIR/genesis-2.txt +rm privateKeyGenesisCells.txt + +echo -e '\n\n' | ckb-cli account new > $ACCOUNTS_DIR/miner.txt +MINER_LOCK_ARG=$(cat $ACCOUNTS_DIR/miner.txt | awk '/lock_arg/ {print $2}') + +create_account "alice" +create_account "bob" + +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 +# 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 + +# Reduce epoch length to 10 blocks. +sed -i 's/genesis_epoch_length = 1000/genesis_epoch_length = 10/' specs/dev.toml +sed -i '/\[params\]/a\ +max_block_bytes = 100_000_000' specs/dev.toml + +# Enable the indexer. +sed -i '/"Debug"]/ s/"Debug"]/"Debug", "Indexer"]/' ckb.toml +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 diff --git a/payment-channel-ckb/devnet/sudt-celldep-template.json b/payment-channel-ckb/devnet/sudt-celldep-template.json new file mode 100644 index 0000000..610cf14 --- /dev/null +++ b/payment-channel-ckb/devnet/sudt-celldep-template.json @@ -0,0 +1,17 @@ +{ + "items": { + "sudt": { + "script_id": { + "hash_type": "data1", + "code_hash": "0x" + }, + "cell_dep": { + "out_point": { + "tx_hash": "0x", + "index": "0x0" + }, + "dep_type": "code" + } + } + } +} diff --git a/payment-channel-ckb/devnet/sudt_helper.sh b/payment-channel-ckb/devnet/sudt_helper.sh new file mode 100755 index 0000000..9bffe39 --- /dev/null +++ b/payment-channel-ckb/devnet/sudt_helper.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +ACCOUNTS_DIR="accounts" +SYSTEM_SCRIPTS_DIR="system_scripts" + +# If any of the listed files is missing, exit with an error. +check_files() { + for file in "$@"; do + if [ ! -f "$file" ]; then + echo "File $file not found. Please run $PWD/print_accounts.sh first and" + echo "make sure $PWD/deploy_contracts.sh has been run successfully." + exit 1 + fi + done +} + +check_files "$ACCOUNTS_DIR/alice.txt" "$ACCOUNTS_DIR/bob.txt" "$ACCOUNTS_DIR/genesis-2.txt" "$SYSTEM_SCRIPTS_DIR/sudt-celldep.json" + +ALICE=$(cat $ACCOUNTS_DIR/alice.txt | awk '/testnet/ { count++; if (count == 1) print $2}') +BOB=$(cat $ACCOUNTS_DIR/bob.txt | awk '/testnet/ { count++; if (count == 1) print $2}') +genesis=$(cat $ACCOUNTS_DIR/genesis-2.txt | awk '/testnet/ { count++; if (count == 2) print $2}') +GENESIS=$(cat $ACCOUNTS_DIR/genesis-2.txt | awk '/testnet/ { count++; if (count == 1) print $2}') + +fund_accounts() { + echo "Funding accounts for Alice and Bob with SUDT tokens" + SUDT_AMOUNT=100000000 + + expect << EOF + spawn ckb-cli sudt issue --owner $GENESIS --udt-to $ALICE:$SUDT_AMOUNT $BOB:$SUDT_AMOUNT --cell-deps $SYSTEM_SCRIPTS_DIR/sudt-celldep.json + expect "owner Password:" + send "\r" + expect eof +EOF +} + +list_accounts_balances() { + echo "Listing SUDT account balances for Alice and Bob" + echo "ALICE: ========================================" + ckb-cli sudt get-amount --owner $GENESIS --cell-deps $SYSTEM_SCRIPTS_DIR/sudt-celldep.json --address $ALICE + echo "BOB: ========================================" + ckb-cli sudt get-amount --owner $GENESIS --cell-deps $SYSTEM_SCRIPTS_DIR/sudt-celldep.json --address $BOB + echo "=============================================" +} + +if [ $# -eq 0 ]; then + echo "No arguments provided. Please provide one of the following:" + echo " balances: list SUDT account balances for Alice and Bob" + echo " fund: fund Alice and Bob with SUDT tokens" + exit 1 +fi + +for arg in "$@"; do + case $arg in + balances) + list_accounts_balances + ;; + fund) + fund_accounts + ;; + *) + echo "Unknown argument: $arg" + echo "Usage: $0 [balances|fund]" + exit 1 + ;; + esac +done diff --git a/payment-channel-ckb/go.mod b/payment-channel-ckb/go.mod new file mode 100644 index 0000000..0907bf1 --- /dev/null +++ b/payment-channel-ckb/go.mod @@ -0,0 +1,114 @@ +module perun.network/perun-ckb-demo + +go 1.17 + +require ( + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 + github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 + github.com/perun-network/perun-libp2p-wire v0.0.0-20240514121025-635388735967 + github.com/stretchr/testify v1.9.0 + perun.network/go-perun v0.10.7-0.20230808153546-74844191e56e + perun.network/perun-ckb-backend v0.0.0-20240514141411-35bdf3afa166 + polycry.pt/poly-go v0.0.0-20220301085937-fb9d71b45a37 +) + +require ( + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Pilatuz/bigz v1.2.1 // indirect + github.com/btcsuite/btcd v0.20.1-beta // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/ethereum/go-ethereum v1.13.10 // indirect + github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gopacket v1.1.17 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/holiman/uint256 v1.2.4 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/go-cid v0.0.7 // indirect + github.com/ipfs/go-ipfs-util v0.0.2 // indirect + github.com/ipfs/go-log v1.0.4 // indirect + github.com/ipfs/go-log/v2 v2.1.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect + github.com/jbenet/goprocess v0.1.4 // indirect + github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d // indirect + github.com/libp2p/go-addr-util v0.0.2 // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect + github.com/libp2p/go-eventbus v0.2.1 // indirect + github.com/libp2p/go-flow-metrics v0.0.3 // indirect + github.com/libp2p/go-libp2p v0.13.0 // indirect + github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect + github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect + github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect + github.com/libp2p/go-libp2p-core v0.8.5 // indirect + github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect + github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect + github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect + github.com/libp2p/go-libp2p-nat v0.0.6 // indirect + github.com/libp2p/go-libp2p-noise v0.1.1 // indirect + github.com/libp2p/go-libp2p-peerstore v0.2.6 // indirect + github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect + github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect + github.com/libp2p/go-libp2p-tls v0.1.3 // indirect + github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect + github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect + github.com/libp2p/go-mplex v0.3.0 // indirect + github.com/libp2p/go-msgio v0.0.6 // indirect + github.com/libp2p/go-nat v0.0.5 // indirect + github.com/libp2p/go-netroute v0.1.3 // indirect + github.com/libp2p/go-openssl v0.0.7 // indirect + github.com/libp2p/go-reuseport v0.0.2 // indirect + github.com/libp2p/go-reuseport-transport v0.0.4 // indirect + github.com/libp2p/go-sockaddr v0.0.2 // indirect + github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect + github.com/libp2p/go-tcp-transport v0.2.1 // indirect + github.com/libp2p/go-ws-transport v0.4.0 // indirect + github.com/libp2p/go-yamux/v2 v2.0.0 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v0.1.1 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multiaddr v0.3.3 // indirect + github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multiaddr-net v0.2.0 // indirect + github.com/multiformats/go-multibase v0.0.3 // indirect + github.com/multiformats/go-multihash v0.0.14 // indirect + github.com/multiformats/go-multistream v0.2.0 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opencensus.io v0.22.4 // indirect + go.uber.org/atomic v1.6.0 // indirect + go.uber.org/multierr v1.5.0 // indirect + go.uber.org/zap v1.15.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/tools v0.17.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/nervosnetwork/ckb-sdk-go/v2 v2.2.0 => github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20230601140721-2bf596fddd80 diff --git a/payment-channel-ckb/go.sum b/payment-channel-ckb/go.sum new file mode 100644 index 0000000..65a8e8c --- /dev/null +++ b/payment-channel-ckb/go.sum @@ -0,0 +1,1754 @@ +cloud.google.com/go v0.0.0-20170206221025-ce650573d812/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0/go.mod h1:ceIuwmxDWptoW3eCqSXlnPsZFKh4X+R38dWPv7GS9Vs= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Pilatuz/bigz v1.2.1 h1:S/R9NGdunq2lIz7KvHu6DmX8bdh41uMqijWeJDz0U5Y= +github.com/Pilatuz/bigz v1.2.1/go.mod h1:FZmplFUEZe3pUr647EQMQgYhV+n9h8+HGTsYK4X6xws= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes= +github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20210923152817-c3b6e2f0c527/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= +github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= +github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= +github.com/aws/aws-sdk-go-v2/config v1.18.45/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= +github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= +github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= +github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2/go.mod h1:TQZBt/WaQy+zTHoW++rnl8JBrmZ0VO6EUbVua1+foCA= +github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= +github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= +github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.9.14/go.mod h1:oP8FC5+TbICUyftkTWs+8JryntjIJLJvWvApK3z2AYw= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= +github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoIVSdqZek= +github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= +github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= +github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= +github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= +github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= +github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= +github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= +github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= +github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= +github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= +github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= +github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= +github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= +github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= +github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= +github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= +github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= +github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= +github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= +github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= +github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= +github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= +github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= +github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= +github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= +github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= +github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= +github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= +github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRhPwSMGpQ= +github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U= +github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= +github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= +github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= +github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= +github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= +github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= +github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= +github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= +github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= +github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= +github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= +github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= +github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= +github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= +github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= +github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= +github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.3 h1:1ngWRx61us/EpaKkdqkMjKk/ufr/JlIFYQAxV2XX8Ig= +github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= +github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= +github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= +github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= +github.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q= +github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= +github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= +github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= +github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= +github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= +github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= +github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= +github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= +github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= +github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU= +github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20230601140721-2bf596fddd80 h1:45S239s+5oGVJHakd+BjfZmstG7wHnA8Tkeq43R9eFA= +github.com/perun-network/ckb-sdk-go/v2 v2.2.1-0.20230601140721-2bf596fddd80/go.mod h1:nPpBML8fuaM1NgkKCwv2gSHiCv+xKH43fu8LA9LOQUg= +github.com/perun-network/perun-libp2p-wire v0.0.0-20240514121025-635388735967 h1:m+63gl1KMpLdseyNEKLnUFrCYipD9Q0Cnf/hmOwAkhs= +github.com/perun-network/perun-libp2p-wire v0.0.0-20240514121025-635388735967/go.mod h1:kA/iWKN+2BvzxuUllMmd1IY6H2oKUZ18U+60hrY19EM= +github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= +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/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +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.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +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/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +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= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ= +google.golang.org/api v0.0.0-20170206182103-3d017632ea10/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20170208002647-2a6bf6142e96/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +perun.network/go-perun v0.10.6/go.mod h1:BGBZC3npkX457u87pjDd0NEIXr1a4dsH4H/YpLdGGe8= +perun.network/go-perun v0.10.7-0.20230808153546-74844191e56e h1:4SOKO0WZtcsQUwP5nKVUrLUohgUPIhMa8wto5iNCA/k= +perun.network/go-perun v0.10.7-0.20230808153546-74844191e56e/go.mod h1:BGBZC3npkX457u87pjDd0NEIXr1a4dsH4H/YpLdGGe8= +perun.network/perun-ckb-backend v0.0.0-20240514141411-35bdf3afa166 h1:Y/3rPrDpspxiMDkh43sV7lkmbSDTM+m37e66kDEidR0= +perun.network/perun-ckb-backend v0.0.0-20240514141411-35bdf3afa166/go.mod h1:Ebp1GCFpmlSlxuP+fSO9yk/qAllF+6GhRCe7b2533zs= +polycry.pt/poly-go v0.0.0-20220222131629-aa4bdbaab60b/go.mod h1:XUBrNtqgEhN3EEOP/5gh7IBd3xVHKidCjXDZfl9+kMU= +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/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/payment-channel-ckb/main.go b/payment-channel-ckb/main.go new file mode 100644 index 0000000..a5db617 --- /dev/null +++ b/payment-channel-ckb/main.go @@ -0,0 +1,285 @@ +package main + +import ( + "errors" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "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" + "perun.network/perun-ckb-backend/channel/asset" + "perun.network/perun-ckb-backend/wallet" + "perun.network/perun-ckb-demo/client" + "perun.network/perun-ckb-demo/deployment" + "polycry.pt/poly-go/sortedkv/memorydb" +) + +const ( + rpcNodeURL = "http://localhost:8114" + Network = types.NetworkTest +) + +func SetLogFile(path string) { + logFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Fatalf("error opening file: %v", err) + } + log.SetOutput(logFile) +} + +func main() { + SetLogFile("demo.log") + 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) + } + /* + maxSudtCapacity := transaction.CalculateCellCapacity(types.CellOutput{ + Capacity: 0, + Lock: &d.DefaultLockScript, + Type: sudtInfo.Script, + }) + */ + 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) + } + + aliceWireAcc := p2p.NewRandomAccount(rand.New(rand.NewSource(time.Now().UnixNano()))) + aliceNet, err := p2p.NewP2PBus(aliceWireAcc) + if err != nil { + log.Fatalf("creating p2p net", err) + } + aliceBus := aliceNet.Bus + aliceListener := aliceNet.Listener + go aliceBus.Listen(aliceListener) + + // Setup clients. + log.Println("Setting up clients.") + //bus := wire.NewLocalBus() // Message bus used for off-chain communication. + prAlice := keyvalue.NewPersistRestorer(memorydb.NewDatabase()) + + alice, err := client.NewPaymentClient( + "Alice", + Network, + d, + rpcNodeURL, + aliceAccount, + *keyAlice, + w, + prAlice, + aliceWireAcc.Address(), + aliceNet, + ) + if err != nil { + 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) + if err != nil { + log.Fatalf("creating p2p net", err) + } + bobBus := bobNet.Bus + bobListener := bobNet.Listener + go bobBus.Listen(bobListener) + + bob, err := client.NewPaymentClient( + "Bob", + Network, + d, + rpcNodeURL, + bobAccount, + *keyBob, + w, + prBob, + bobWireAcc.Address(), + bobNet, + ) + if err != nil { + log.Fatalf("error creating bob's client: %v", err) + } + + //print balances before transaction + + fmt.Println("Balances of Alice and Bob before transaction") + str := "'s account balance" + fmt.Println(alice.Name, str, alice.GetBalances()) + fmt.Println(bob.Name, str, bob.GetBalances()) + + ckbAsset := asset.Asset{ + IsCKBytes: true, + SUDT: nil, + } + + /* + sudtAsset := asset.Asset{ + IsCKBytes: false, + SUDT: &asset.SUDT{ + TypeScript: *sudtInfo.Script, + MaxCapacity: maxSudtCapacity, + }, + } + */ + + fmt.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, + }) + strAlice := "Alice" + strBob := "Bob" + fmt.Println(alice.Name, str, alice.GetBalances()) + fmt.Println(bob.Name, str, bob.GetBalances()) + + fmt.Println("Alice sent proposal") + chBob := bob.AcceptedChannel() + fmt.Println("Bob accepted proposal") + fmt.Println("Sending payments....") + + chAlice.SendPayment(map[channel.Asset]float64{ + &ckbAsset: 10.0, + }) + fmt.Println("Alice sent Bob a payment") + printAllocationBalances(chAlice, ckbAsset, strAlice) + printAllocationBalances(chBob, ckbAsset, strBob) + + chBob.SendPayment(map[channel.Asset]float64{ + &ckbAsset: 10.0, + }) + fmt.Println("Bob sent Alice a payment") + printAllocationBalances(chAlice, ckbAsset, strAlice) + printAllocationBalances(chBob, ckbAsset, strBob) + + chAlice.SendPayment(map[channel.Asset]float64{ + &ckbAsset: 10.0, + }) + fmt.Println("Alice sent Bob a payment") + printAllocationBalances(chAlice, ckbAsset, strAlice) + printAllocationBalances(chBob, ckbAsset, strBob) + + fmt.Println("Payments completed") + printAllocationBalances(chAlice, ckbAsset, strAlice) + printAllocationBalances(chBob, ckbAsset, strBob) + + fmt.Println("Skip Settling Channel and force client shutdown") + //chAlice.Settle() + + fmt.Println(alice.Name, str, alice.GetBalances()) + fmt.Println(bob.Name, str, bob.GetBalances()) + + //cleanup + alice.Shutdown() + bob.Shutdown() + fmt.Println("Clients shutdown, exiting method") + + fmt.Println("Creating clients again to see if channels can be restored") + alice2, err := client.NewPaymentClient( + "Alice", + Network, + d, + rpcNodeURL, + aliceAccount, + *keyAlice, + w, + prAlice, + alice.WireAddress(), + aliceNet, + ) + if err != nil { + log.Fatalf("error creating alice's client: %v", err) + } + bob2, err := client.NewPaymentClient( + "Bob", + Network, + d, + rpcNodeURL, + bobAccount, + *keyBob, + w, + prBob, + bob.WireAddress(), + bobNet, + ) + if err != nil { + log.Fatalf("error creating bob's client: %v", err) + } + fmt.Println("Starting restoring channels") + chansAlice := alice2.Restore(bob2.WireAddress(), bob2.PeerID()) + fmt.Println("Alice's channel restored") + chansBob := bob2.Restore(alice2.WireAddress(), alice2.PeerID()) + fmt.Println("Alice and Bob's channels successfully restored") + + // Print balances after transactions. + fmt.Println(alice.Name, str, alice.GetBalances()) + fmt.Println(bob.Name, str, bob.GetBalances()) + + fmt.Println("Alice sending payment to Bob") + chansAlice[0].SendPayment(map[channel.Asset]float64{ + &ckbAsset: 10.0, + }) + fmt.Println("Bob sending payment to Alice") + chansBob[0].SendPayment(map[channel.Asset]float64{ + &ckbAsset: 10.0, + }) + + chansAlice[0].Settle() + fmt.Println("Balances after settling channel") + fmt.Println(alice.Name, str, alice.GetBalances()) + fmt.Println(bob.Name, str, bob.GetBalances()) + +} + +func printAllocationBalances(ch *client.PaymentChannel, asset asset.Asset, name string) { + chAlloc := ch.State().Allocation + //_assets := chAlloc.Assets + fmt.Println("Assets held by" + name) + /* + for _, a := range _assets { + fmt.Println(a) + } + */ + fmt.Println(name + "'s allocation in channel: " + chAlloc.Balance(1, &asset).String()) +} + +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/client/client.go b/payment-channel/client/client.go index 6aa696c..6f1baab 100644 --- a/payment-channel/client/client.go +++ b/payment-channel/client/client.go @@ -163,4 +163,4 @@ func (c *PaymentClient) AcceptedChannel() *PaymentChannel { // Shutdown gracefully shuts down the client. func (c *PaymentClient) Shutdown() { c.perunClient.Close() -} +} \ No newline at end of file