diff --git a/Readme.md b/Readme.md index 3302a7d..78210eb 100644 --- a/Readme.md +++ b/Readme.md @@ -15,7 +15,7 @@ and scalability of a declarative transaction model such as Bitcoin's. * [TxVM White Paper](https://chain.com/assets/txvm.pdf) * [TxVM Specification](specifications/txvm.md) -* [Documentation for TxVM command line tools](https://godoc.org/github.com/chain/txvm) +* [Documentation for TxVM command line tools](https://godoc.org/github.com/bobg/txvm) * [Presentation](https://www.youtube.com/watch?v=qY_0MJDMBNY) and [slides](https://cyber.stanford.edu/sites/default/files/txvm_stanford_jan24.pdf) @@ -31,13 +31,13 @@ Details [here](https://golang.org/cmd/go/#hdr-Preliminary_module_support). Run the following command: ```sh -go get github.com/chain/txvm/... +go get github.com/bobg/txvm/... ``` ## Testing ```sh -go test -race -cover github.com/chain/txvm/... +go test -race -cover github.com/bobg/txvm/... ``` ## Usage @@ -70,7 +70,7 @@ To compute its transaction log: For more on the commands `txvm` makes available, you can check out the -[documentation](https://godoc.org/github.com/chain/txvm). +[documentation](https://godoc.org/github.com/bobg/txvm). ## Contributing diff --git a/cmd/asm/asm.go b/cmd/asm/asm.go index b614f5f..fa9a77c 100644 --- a/cmd/asm/asm.go +++ b/cmd/asm/asm.go @@ -1,44 +1,24 @@ package main import ( + "context" "flag" "fmt" - "io/ioutil" "os" - "github.com/chain/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/cmd/internal/asm" ) func main() { - doDisasm := flag.Bool("d", false, "disassemble") - flag.Parse() - if *doDisasm { - disassemble() - } else { - assemble() + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) } } -func assemble() { - src, err := ioutil.ReadAll(os.Stdin) - if err != nil { - panic(err) - } - res, err := asm.Assemble(string(src)) - if err != nil { - panic(err) - } - os.Stdout.Write(res) -} +func run() error { + doDisasm := flag.Bool("d", false, "disassemble") + flag.Parse() -func disassemble() { - b, err := ioutil.ReadAll(os.Stdin) - if err != nil { - panic(err) - } - dis, err := asm.Disassemble(b) - if err != nil { - panic(err) - } - fmt.Println(dis) + return asm.Run(context.Background(), *doDisasm, nil) } diff --git a/cmd/asm/doc.go b/cmd/asm/doc.go index 56b2f97..19a4efe 100644 --- a/cmd/asm/doc.go +++ b/cmd/asm/doc.go @@ -1,5 +1,4 @@ /* - Command asm assembles and disassembles Usage: @@ -18,6 +17,5 @@ Examples: $ echo "6101303833" | hex -d | asm -d [1 verify] contract call - */ package main diff --git a/cmd/assetid/assetid.go b/cmd/assetid/assetid.go index 7d36693..f2ff743 100644 --- a/cmd/assetid/assetid.go +++ b/cmd/assetid/assetid.go @@ -1,50 +1,36 @@ package main import ( - "encoding/hex" + "context" "flag" "fmt" "os" "strconv" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/txbuilder/standard" + "github.com/bobg/txvm/cmd/internal/assetid" + "github.com/bobg/txvm/errors" ) func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } +} + +func run() error { tagHex := flag.String("t", "", "hex asset tag") - help := flag.Bool("h", false, "help") version := flag.Int("v", 2, "asset contract version") flag.Parse() - if *help { - usage(0) - } - tag, err := hex.DecodeString(*tagHex) - must(err) - if flag.NArg() < 2 { - usage(1) - } - quorum, err := strconv.Atoi(flag.Arg(0)) - must(err) - var pubkeys []ed25519.PublicKey - for i := 1; i < flag.NArg(); i++ { - pubkey, err := hex.DecodeString(flag.Arg(1)) - must(err) - pubkeys = append(pubkeys, ed25519.PublicKey(pubkey)) - } - assetID := standard.AssetID(*version, quorum, pubkeys, tag) - _, err = os.Stdout.Write(assetID[:]) - must(err) -} -func usage(exitval int) { - fmt.Println("Usage:") - fmt.Printf("\t%s [-t taghex] quorum pubkey1hex pubkey2hex ...\n", os.Args[0]) - os.Exit(exitval) -} + if flag.NArg() == 0 { + return fmt.Errorf("must provide quorum and at least one public key") + } -func must(err error) { + quorum, err := strconv.Atoi(flag.Arg(0)) if err != nil { - panic(err) + return errors.Wrap(err, "parsing quorum") } + + return assetid.Run(context.Background(), *tagHex, *version, quorum, flag.Args()[1:]) } diff --git a/cmd/assetid/doc.go b/cmd/assetid/doc.go index cea3e33..c9f28b7 100644 --- a/cmd/assetid/doc.go +++ b/cmd/assetid/doc.go @@ -1,11 +1,9 @@ /* - Command assetid produces an asset ID from an initial contract program and an optional asset tag (default empty). Usage: assetid [-t taghex] [-v contract-version] quorum pubkey1hex pubkey2hex ... - */ package main diff --git a/cmd/bcstate/bcstate.go b/cmd/bcstate/bcstate.go index 761dc0a..9a87683 100644 --- a/cmd/bcstate/bcstate.go +++ b/cmd/bcstate/bcstate.go @@ -1,82 +1,27 @@ package main import ( + "context" "flag" - "io" - "io/ioutil" - "log" + "fmt" "os" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/cmd/internal/bcstate" ) func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } +} + +func run() error { var ( blockFile = flag.String("block", "", "filename containing block to apply") stateFile = flag.String("state", "", "filename containing previous state") ) - flag.Parse() - if *blockFile == "-" && *stateFile == "-" { - log.Fatal("only one of -block and -state may be -") - } - - blockInp := getReader(*blockFile) - if blockInp != nil { - defer blockInp.Close() - } - - stateInp := getReader(*stateFile) - if stateInp != nil { - defer stateInp.Close() - } - - var snapshot *state.Snapshot - - if stateInp == nil { - snapshot = state.Empty() - } else { - b, err := ioutil.ReadAll(stateInp) - must(err) - snapshot = new(state.Snapshot) - err = snapshot.FromBytes(b) - must(err) - } - - if blockInp != nil { - b, err := ioutil.ReadAll(blockInp) - must(err) - var block bc.Block - err = block.FromBytes(b) - must(err) - err = snapshot.ApplyBlock(block.UnsignedBlock) - if err != nil { - log.Fatal(err) - } - } - - b, err := snapshot.Bytes() - must(err) - os.Stdout.Write(b) -} - -func getReader(arg string) io.ReadCloser { - switch arg { - case "": - return nil - case "-": - return os.Stdin - default: - f, err := os.Open(arg) - must(err) - return f - } -} - -func must(err error) { - if err != nil { - panic(err) - } + return bcstate.Run(context.Background(), *blockFile, *stateFile, flag.Args()) } diff --git a/cmd/bcstate/doc.go b/cmd/bcstate/doc.go index f95549e..c1f586a 100644 --- a/cmd/bcstate/doc.go +++ b/cmd/bcstate/doc.go @@ -1,5 +1,4 @@ /* - Command bcstate reads and writes blockchain state, optionally applying a block. @@ -16,6 +15,5 @@ BLOCKFILE is applied to it, and the resulting updated state is written to standard output. If STATEFILE is not specified then a new blank state snapshot is used. If BLOCKFILE is not specified then the input state is simply copied to standard output. - */ package main diff --git a/cmd/block/block.go b/cmd/block/block.go index 2042366..864a7ca 100644 --- a/cmd/block/block.go +++ b/cmd/block/block.go @@ -1,393 +1,20 @@ package main import ( - "encoding/hex" - "flag" + "context" "fmt" - "io/ioutil" "os" - "strconv" - "strings" - "time" - "github.com/golang/protobuf/proto" - - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/state" - "github.com/chain/txvm/protocol/validation" + "github.com/bobg/txvm/cmd/internal/block" ) -var modes = map[string]func([]string){ - "build": build, - "hash": hash, - "header": header, - "new": newBlock, - "sign": sign, - "tx": tx, - "validate": validate, -} - func main() { - if len(os.Args) < 2 { - usage() - } - - mode := os.Args[1] - fn, ok := modes[mode] - if !ok { - usage() - } - - fn(os.Args[2:]) -} - -func build(args []string) { - fs := flag.NewFlagSet("build", flag.PanicOnError) - - var ( - timeStr = fs.String("time", "", "block timestamp") - snapOut = fs.String("snapout", "", "output file for snapshot") - ) - - err := fs.Parse(args) - must(err) - - var ts time.Time - if *timeStr == "" { - ts = time.Now() - } else { - ts, err = time.Parse(time.RFC3339, *timeStr) - must(err) - } - timestampMS := bc.Millis(ts) - - bb := protocol.NewBlockBuilder() - - snapshotBits, err := ioutil.ReadAll(os.Stdin) - must(err) - snapshot := new(state.Snapshot) - err = snapshot.FromBytes(snapshotBits) - must(err) - - err = bb.Start(snapshot, timestampMS) - must(err) - - for _, arg := range fs.Args() { - txbits, err := ioutil.ReadFile(arg) - must(err) - rawTx := new(bc.RawTx) - err = proto.Unmarshal(txbits, rawTx) - must(err) - tx, err := bc.NewTx(rawTx.Program, rawTx.Version, rawTx.Runlimit) - must(err) - err = bb.AddTx(bc.NewCommitmentsTx(tx)) - must(err) - } - - ub, newSnapshot, err := bb.Build() - must(err) - - if *snapOut != "" { - newSnapshotBytes, err := newSnapshot.Bytes() - err = ioutil.WriteFile(*snapOut, newSnapshotBytes, 0644) - must(err) - } - - b := &bc.Block{UnsignedBlock: ub} - bbytes, err := b.Bytes() - must(err) - - os.Stdout.Write(bbytes) -} - -func newBlock(args []string) { - fs := flag.NewFlagSet("new", flag.PanicOnError) - - var ( - quorum = fs.Int("quorum", 0, "number of signatures required to authorize block") - timeStr = fs.String("time", "", "block timestamp") - ) - - err := fs.Parse(args) - must(err) - - pubkeysHex := fs.Args() - var pubkeys []ed25519.PublicKey - for _, pubkeyHex := range pubkeysHex { - b, err := hex.DecodeString(pubkeyHex) - must(err) - if len(b) != ed25519.PublicKeySize { - panic(fmt.Errorf("bad pubkey length %d, want 32", len(b))) - } - pubkeys = append(pubkeys, ed25519.PublicKey(b)) - } - - if *quorum < 0 || *quorum > len(pubkeys) { - panic(fmt.Errorf("-quorum must be between 1 and %d", len(pubkeys))) - } - if *quorum == 0 { - // There may be zero pubkeys, in which case *quorum will remain - // zero. But if there are any pubkeys then quorum should be at - // least 1. - *quorum = len(pubkeys) - } - - var ts time.Time - if *timeStr == "" { - ts = time.Now() - } else { - ts, err = time.Parse(time.RFC3339, *timeStr) - must(err) - } - - block, err := protocol.NewInitialBlock(pubkeys, *quorum, ts) - must(err) - - blockBytes, err := block.Bytes() - must(err) - - os.Stdout.Write(blockBytes) -} - -func sign(args []string) { - fs := flag.NewFlagSet("sign", flag.PanicOnError) - prevHex := fs.String("prev", "", "previous block header (hex)") - err := fs.Parse(args) - must(err) - - prevBytes, err := hex.DecodeString(*prevHex) - must(err) - - var prev bc.BlockHeader - err = proto.Unmarshal(prevBytes, &prev) - must(err) - - blockBytes, err := ioutil.ReadAll(os.Stdin) - must(err) - - block := new(bc.Block) - err = block.FromBytes(blockBytes) - must(err) - - hash := block.Hash().Bytes() - - block, err = bc.SignBlock(block.UnsignedBlock, &prev, func(idx int) (interface{}, error) { - if arg := fs.Arg(idx); arg != "" { - prv, err := hex.DecodeString(arg) - must(err) - return ed25519.Sign(prv, hash), nil - } - return nil, nil - }) - must(err) - - blockBytes, err = block.Bytes() - must(err) - - os.Stdout.Write(blockBytes) -} - -func validate(args []string) { - fs := flag.NewFlagSet("validate", flag.PanicOnError) - - var ( - prevHex = fs.String("prev", "", "previous block header (hex)") - noSig = fs.Bool("nosig", false, "skip signature validation") - noPrev = fs.Bool("noprev", false, "skip validation against previous block") - ) - - err := fs.Parse(args) - must(err) - - inp, err := ioutil.ReadAll(os.Stdin) - must(err) - - var b bc.Block - err = b.FromBytes(inp) - if err != nil { - fmt.Fprintln(os.Stderr, err) + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) os.Exit(1) } - - if *prevHex != "" { - prevBytes, err := hex.DecodeString(*prevHex) - must(err) - - var prev bc.BlockHeader - err = proto.Unmarshal(prevBytes, &prev) - must(err) - - err = validation.Block(b.UnsignedBlock, &prev) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - - // TODO(bobg): consider a way to validate the ConsensusRoot and - // NoncesRoot too - - if !*noSig { - err = validation.BlockSig(&b, prev.NextPredicate) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - } - return - } - - if b.Height == 1 || *noPrev { - err = validation.BlockOnly(b.UnsignedBlock) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - return - } - - fmt.Fprintln(os.Stderr, "previous blockheader not supplied") - os.Exit(1) -} - -func hash(_ []string) { - inp, err := ioutil.ReadAll(os.Stdin) - must(err) - - var ( - bh *bc.BlockHeader - rb bc.RawBlock - ) - err = proto.Unmarshal(inp, &rb) - if err != nil { - bh = new(bc.BlockHeader) - err = proto.Unmarshal(inp, bh) - must(err) - } else { - bh = rb.Header - } - h := bh.Hash() - os.Stdout.Write(h.Bytes()) -} - -func header(args []string) { - fs := flag.NewFlagSet("header", flag.PanicOnError) - pretty := fs.Bool("pretty", false, "show individual blockheader fields") - - err := fs.Parse(args) - must(err) - - inp, err := ioutil.ReadAll(os.Stdin) - must(err) - - var rb bc.RawBlock - err = proto.Unmarshal(inp, &rb) - must(err) - - if *pretty { - var ( - bh = rb.Header - pubkeys []string - ) - - for _, p := range bh.NextPredicate.Pubkeys { - pubkeys = append(pubkeys, hex.EncodeToString(p)) - } - - fmt.Printf("Version: %d\n", bh.Version) - fmt.Printf("Height: %d\n", bh.Height) - if bh.PreviousBlockId != nil { - fmt.Printf("PreviousBlockId: %x\n", bh.PreviousBlockId.Bytes()) - } else { - fmt.Printf("PreviousBlockId: nil\n") - } - fmt.Printf("TimestampMs: %d\n", bh.TimestampMs) - fmt.Printf("Runlimit: %d\n", bh.Runlimit) - fmt.Printf("RefsCount: %d\n", bh.RefsCount) - fmt.Printf("TransactionsRoot: %x\n", bh.TransactionsRoot.Bytes()) - fmt.Printf("ContractsRoot: %x\n", bh.ContractsRoot.Bytes()) - fmt.Printf("NoncesRoot: %x\n", bh.NoncesRoot.Bytes()) - fmt.Printf("NextPredicate.Version: %d\n", bh.NextPredicate.Version) - fmt.Printf("NextPredicate.Quorum: %d\n", bh.NextPredicate.Quorum) - fmt.Printf("NextPredicate.Pubkeys: %s\n", strings.Join(pubkeys, " ")) - fmt.Printf("Transactions: %d\n", len(rb.Transactions)) - return - } - - headerBytes, err := proto.Marshal(rb.Header) - must(err) - - os.Stdout.Write(headerBytes) -} - -func tx(args []string) { - fs := flag.NewFlagSet("tx", flag.PanicOnError) - - var ( - raw = fs.Bool("raw", false, "emit raw tx") - pretty = fs.Bool("pretty", false, "show individual tx fields") - ) - - err := fs.Parse(args) - must(err) - - args = fs.Args() - if len(args) < 1 { - usage() - } - - idx, err := strconv.Atoi(args[0]) - must(err) - - if idx < 0 { - panic("index out of range") - } - - inp, err := ioutil.ReadAll(os.Stdin) - must(err) - - var rb bc.RawBlock - err = proto.Unmarshal(inp, &rb) - must(err) - - if idx >= len(rb.Transactions) { - panic("index out of range") - } - - tx := rb.Transactions[idx] - - if *raw { - txBytes, err := proto.Marshal(tx) - must(err) - os.Stdout.Write(txBytes) - return - } - - if *pretty { - fmt.Printf("Version: %d\n", tx.Version) - fmt.Printf("Runlimit: %d\n", tx.Runlimit) - fmt.Printf("Program: %x\n", tx.Program) - return - } - - os.Stdout.Write(tx.Program) -} - -func must(err error) { - if err != nil { - panic(err) - } } -func usage() { - fmt.Fprintln(os.Stderr, "Usage:") - fmt.Fprintln(os.Stderr, " block validate [-prev PREVHEX] [-nosig] [-noprev] BLOCK") - fmt.Fprintln(os.Stderr, " block build [-time TIME] [-snapout FILE] TXFILE TXFILE ... BLOCK") - fmt.Fprintln(os.Stderr, " block sign -prev PREVHEX PRVHEX PRVHEX ... BLOCK") - os.Exit(1) +func run() error { + return block.Run(context.Background(), os.Args[1:]) } diff --git a/cmd/block/doc.go b/cmd/block/doc.go index b83ee70..cb02afb 100644 --- a/cmd/block/doc.go +++ b/cmd/block/doc.go @@ -1,5 +1,4 @@ /* - Command block parses Chain protocol blocks and performs various operations on them. @@ -75,6 +74,5 @@ producing the output block. The hash subcommand accepts a block or a block header as input (such as is produced by the output of the header subcommand). The output is the hash of the block header that also serves as the ID of the block. - */ package main diff --git a/cmd/ed25519/doc.go b/cmd/ed25519/doc.go index 4a2730f..fb03700 100644 --- a/cmd/ed25519/doc.go +++ b/cmd/ed25519/doc.go @@ -1,5 +1,4 @@ /* - Command ed25519 creates and manipulates ed25519 public and private keys. Usage: @@ -16,6 +15,5 @@ The verify subcommand verifies a signature with a message and a public key. The verify subcommand prints "OK" or "BAD" to stdout unless the -s ("silent") flag is given. The program exits with 0 when the signature is verified, nonzero when it's not. - */ package main diff --git a/cmd/ed25519/ed25519.go b/cmd/ed25519/ed25519.go index 53208e5..ca4fce2 100644 --- a/cmd/ed25519/ed25519.go +++ b/cmd/ed25519/ed25519.go @@ -1,99 +1,20 @@ package main import ( - "encoding/hex" + "context" "fmt" - "io/ioutil" "os" - "github.com/chain/txvm/crypto/ed25519" + "github.com/bobg/txvm/cmd/internal/ed25519" ) func main() { - if len(os.Args) < 2 { - usage() - } - switch os.Args[1] { - case "gen": - _, prv, err := ed25519.GenerateKey(nil) - must(err) - os.Stdout.Write(prv) - - case "pub": - prv, err := ioutil.ReadAll(os.Stdin) - must(err) - pub := ed25519.PrivateKey(prv).Public().(ed25519.PublicKey) - os.Stdout.Write([]byte(pub)) - - case "sign": - if len(os.Args) < 3 { - usage() - } - prvhex := os.Args[2] - prv, err := hex.DecodeString(prvhex) - must(err) - msg, err := ioutil.ReadAll(os.Stdin) - must(err) - sig := ed25519.Sign(ed25519.PrivateKey(prv), msg) - os.Stdout.Write(sig) - - case "verify": - args := os.Args[2:] - if len(args) < 1 { - usage() - } - var silent bool - if args[0] == "-s" { - silent = true - args = args[1:] - } - if len(args) < 2 { - usage() - } - pub, err := hex.DecodeString(args[0]) - must(err) - sig, err := hex.DecodeString(args[1]) - must(err) - msg, err := ioutil.ReadAll(os.Stdin) - must(err) - ok := ed25519.Verify(ed25519.PublicKey(pub), msg, sig) - if !silent { - if ok { - fmt.Println("OK") - } else { - fmt.Println("BAD") - } - } - if !ok { - os.Exit(1) - } - - default: - usage() + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) } } -func must(err error) { - if err != nil { - panic(err) - } -} - -func usage() { - opts := []string{ - "gen >privatekey", - "pub publickey", - "sign PRIVHEX signature", - "verify [-s] PUBHEX SIGHEX = 2 { - r = &splitLineReader{r: r, max: *lineLen - *lineLen%2} - } - if decode { - r = &decodeReader{r: &stripSpaceReader{os.Stdin}} + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) } - _, err := io.Copy(os.Stdout, r) - if err != nil { - log.Fatal(err) - } -} - -type encodeReader struct { - r io.Reader } -func (r *encodeReader) Read(p []byte) (int, error) { - if len(p)%2 == 1 { - p = p[:len(p)-1] - } - h := p[len(p)/2:] - n, err := r.r.Read(h) - return hex.Encode(p, h[:n]), err -} - -type splitLineReader struct { - r io.Reader - n int - max int -} - -func (r *splitLineReader) Read(p []byte) (int, error) { - if len(p) == 0 { - return 0, nil - } - p = p[:len(p)-1] // leave room for possible '\n' below - if len(p) > r.max-r.n { - p = p[:r.max-r.n] - } - n, err := r.r.Read(p) - p = p[:n] - r.n += n - if r.n >= r.max || err == io.EOF { - p = p[:n+1] - p[n] = '\n' - r.n = 0 - } - return len(p), err -} +func run() error { + var ( + decode bool + lineLen int + ) -type decodeReader struct { - r io.Reader - par int // parity of last read (0 or 1) - b byte // odd byte from last read (if any) -} - -func (r *decodeReader) Read(p []byte) (int, error) { - if len(p) == 0 { - return 0, nil - } - if r.par == 1 { - p[0] = r.b - } - n, err := r.r.Read(p[r.par:]) - p = p[:r.par+n] - r.par = len(p) % 2 - if r.par == 1 { - r.b = p[len(p)-1] - p = p[:len(p)-1] - } - d, err1 := hex.Decode(p, p) - if err1 != nil { - return d, err1 - } - if r.par == 1 && err == io.EOF { - err = hex.ErrLength - } - return d, err -} - -type stripSpaceReader struct { - r io.Reader -} - -func (r *stripSpaceReader) Read(p []byte) (int, error) { - n, err := r.r.Read(p) - w := 0 - for _, b := range p[:n] { - if !isSpace(b) { - p[w] = b - w++ - } - } - return w, err -} + flag.BoolVar(&decode, "d", false, "decode (negates -e)") + flagNotBoolVar(&decode, "e", true, "encode (negates -d) (default true)") + flag.IntVar(&lineLen, "n", math.MaxInt32, "max encoded output line length") + flag.Parse() -func isSpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' + return hex.Run(context.Background(), decode, lineLen, flag.Args()) } diff --git a/cmd/internal/asm/asm.go b/cmd/internal/asm/asm.go new file mode 100644 index 0000000..c695687 --- /dev/null +++ b/cmd/internal/asm/asm.go @@ -0,0 +1,44 @@ +package asm + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/asm" +) + +func Run(_ context.Context, doDisasm bool, _ []string) error { + if doDisasm { + return disassemble() + } + return assemble() +} + +func assemble() error { + src, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading input") + } + res, err := asm.Assemble(string(src)) + if err != nil { + return errors.Wrap(err, "assembling") + } + _, err = os.Stdout.Write(res) + return errors.Wrap(err, "writing output") +} + +func disassemble() error { + b, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading input") + } + dis, err := asm.Disassemble(b) + if err != nil { + return errors.Wrap(err, "disassembling") + } + _, err = fmt.Println(dis) + return errors.Wrap(err, "writing output") +} diff --git a/cmd/internal/assetid/assetid.go b/cmd/internal/assetid/assetid.go new file mode 100644 index 0000000..ee36a47 --- /dev/null +++ b/cmd/internal/assetid/assetid.go @@ -0,0 +1,30 @@ +package assetid + +import ( + "context" + "encoding/hex" + "os" + + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txbuilder/standard" +) + +func Run(_ context.Context, tagHex string, version, quorum int, pubkeyHexs []string) error { + tag, err := hex.DecodeString(tagHex) + if err != nil { + return errors.Wrap(err, "decoding hex tag") + } + + var pubkeys []ed25519.PublicKey + for _, pubkeyHex := range pubkeyHexs { + pubkey, err := hex.DecodeString(pubkeyHex) + if err != nil { + return errors.Wrapf(err, "decoding pubkey hex %s", pubkeyHex) + } + pubkeys = append(pubkeys, ed25519.PublicKey(pubkey)) + } + assetID := standard.AssetID(version, quorum, pubkeys, tag) + _, err = os.Stdout.Write(assetID[:]) + return errors.Wrap(err, "writing asset ID") +} diff --git a/cmd/internal/bcstate/bcstate.go b/cmd/internal/bcstate/bcstate.go new file mode 100644 index 0000000..8a7877a --- /dev/null +++ b/cmd/internal/bcstate/bcstate.go @@ -0,0 +1,81 @@ +package bcstate + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/state" +) + +func Run(_ context.Context, blockFile, stateFile string, _ []string) error { + if blockFile == "-" && stateFile == "-" { + return fmt.Errorf("only one of -block and -state may be -") + } + + blockInp, err := getReader(blockFile) + if err != nil { + return errors.Wrap(err, "getting block reader") + } + if blockInp != nil { + defer blockInp.Close() + } + + stateInp, err := getReader(stateFile) + if err != nil { + return errors.Wrap(err, "getting state reader") + } + if stateInp != nil { + defer stateInp.Close() + } + + var snapshot *state.Snapshot + + if stateInp == nil { + snapshot = state.Empty() + } else { + b, err := io.ReadAll(stateInp) + if err != nil { + return errors.Wrap(err, "reading state input") + } + snapshot = new(state.Snapshot) + if err = snapshot.FromBytes(b); err != nil { + return errors.Wrap(err, "parsing state snapshot") + } + } + + if blockInp != nil { + b, err := io.ReadAll(blockInp) + if err != nil { + return errors.Wrap(err, "reading block input") + } + var block bc.Block + if err = block.FromBytes(b); err != nil { + return errors.Wrap(err, "parsing block") + } + if err = snapshot.ApplyBlock(block.UnsignedBlock); err != nil { + return errors.Wrap(err, "applying block to state") + } + } + + b, err := snapshot.Bytes() + if err != nil { + return errors.Wrap(err, "serializing resulting state snapshot") + } + _, err = os.Stdout.Write(b) + return errors.Wrap(err, "writing resulting state snapshot") +} + +func getReader(arg string) (io.ReadCloser, error) { + switch arg { + case "": + return nil, nil + case "-": + return os.Stdin, nil + default: + return os.Open(arg) + } +} diff --git a/cmd/internal/block/block.go b/cmd/internal/block/block.go new file mode 100644 index 0000000..8536104 --- /dev/null +++ b/cmd/internal/block/block.go @@ -0,0 +1,391 @@ +package block + +import ( + "context" + "encoding/hex" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/bobg/subcmd/v2" + "github.com/golang/protobuf/proto" + + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/state" + "github.com/bobg/txvm/protocol/validation" +) + +func Run(ctx context.Context, args []string) error { + return subcmd.Run(ctx, cmd{}, args) +} + +type cmd struct{} + +func (c cmd) Subcmds() subcmd.Map { + return subcmd.Commands( + "build", doBuild, "build a block from transactions", subcmd.Params( + "-time", subcmd.String, "", "block timestamp in RFC3339 format (default current time)", + "-snapout", subcmd.String, "", "output file for snapshot", + ), + "hash", doHash, "compute the hash of a block", nil, + "header", doHeader, "extract the header from a block", subcmd.Params( + "-pretty", subcmd.Bool, false, "pretty-print the header", + ), + "new", doNew, "create a new block at height 1", subcmd.Params( + "-quorum", subcmd.Int, 0, "number of signatures required", + "-time", subcmd.String, "", "block timestamp in RFC3339 format (default current time)", + ), + "sign", doSign, "sign a block with private keys", subcmd.Params( + "-prev", subcmd.String, "", "hex of previous block header", + ), + "tx", doTx, "extract a transaction from a block", subcmd.Params( + "-raw", subcmd.Bool, false, "output raw txwitness", + "-pretty", subcmd.Bool, false, "pretty-print the txwitness", + "index", subcmd.Int, 0, "zero-based index of transaction to extract", + ), + "validate", doValidate, "validate a block", subcmd.Params( + "-prev", subcmd.String, "", "hex of previous block header", + "-noprev", subcmd.Bool, false, "skip previous block checks", + "-nosig", subcmd.Bool, false, "skip signature checks", + ), + ) +} + +func doBuild(_ context.Context, timeStr, snapOut string, args []string) error { + var ts time.Time + if timeStr == "" { + ts = time.Now() + } else { + var err error + ts, err = time.Parse(time.RFC3339, timeStr) + if err != nil { + return errors.Wrap(err, "parsing time") + } + } + timestampMS := bc.Millis(ts) + + bb := protocol.NewBlockBuilder() + + snapshotBits, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading snapshot from stdin") + } + + snapshot := new(state.Snapshot) + if err = snapshot.FromBytes(snapshotBits); err != nil { + return errors.Wrap(err, "parsing snapshot") + } + + if err = bb.Start(snapshot, timestampMS); err != nil { + return errors.Wrap(err, "starting block builder") + } + + for _, arg := range args { + txbits, err := os.ReadFile(arg) + if err != nil { + return errors.Wrapf(err, "reading tx file %s", arg) + } + + rawTx := new(bc.RawTx) + if err = proto.Unmarshal(txbits, rawTx); err != nil { + return errors.Wrapf(err, "parsing raw tx from file %s", arg) + } + + tx, err := bc.NewTx(rawTx.Program, rawTx.Version, rawTx.Runlimit) + if err != nil { + return errors.Wrapf(err, "constructing tx from file %s", arg) + } + + if err = bb.AddTx(bc.NewCommitmentsTx(tx)); err != nil { + return errors.Wrapf(err, "adding tx from file %s to block", arg) + } + } + + ub, newSnapshot, err := bb.Build() + if err != nil { + return errors.Wrap(err, "building block") + } + + if snapOut != "" { + newSnapshotBytes, err := newSnapshot.Bytes() + if err != nil { + return errors.Wrap(err, "serializing snapshot") + } + if err = os.WriteFile(snapOut, newSnapshotBytes, 0644); err != nil { + return errors.Wrap(err, "writing snapshot to file") + } + } + + b := &bc.Block{UnsignedBlock: ub} + bbytes, err := b.Bytes() + if err != nil { + return errors.Wrap(err, "serializing block") + } + + _, err = os.Stdout.Write(bbytes) + return errors.Wrap(err, "writing block to stdout") +} + +func doHash(_ context.Context, _ []string) error { + inp, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading block from stdin") + } + + var ( + bh *bc.BlockHeader + rb bc.RawBlock + ) + err = proto.Unmarshal(inp, &rb) + if err != nil { + bh = new(bc.BlockHeader) + if err = proto.Unmarshal(inp, bh); err != nil { + return errors.Wrap(err, "parsing block header") + } + } else { + bh = rb.Header + } + + h := bh.Hash() + _, err = os.Stdout.Write(h.Bytes()) + return errors.Wrap(err, "writing block hash to stdout") +} + +func doHeader(_ context.Context, pretty bool, _ []string) error { + inp, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading block from stdin") + } + + var rb bc.RawBlock + if err = proto.Unmarshal(inp, &rb); err != nil { + return errors.Wrap(err, "parsing raw block") + } + + if pretty { + var ( + bh = rb.Header + pubkeys []string + ) + + for _, p := range bh.NextPredicate.Pubkeys { + pubkeys = append(pubkeys, hex.EncodeToString(p)) + } + + fmt.Printf("Version: %d\n", bh.Version) + fmt.Printf("Height: %d\n", bh.Height) + if bh.PreviousBlockId != nil { + fmt.Printf("PreviousBlockId: %x\n", bh.PreviousBlockId.Bytes()) + } else { + fmt.Printf("PreviousBlockId: nil\n") + } + fmt.Printf("TimestampMs: %d\n", bh.TimestampMs) + fmt.Printf("Runlimit: %d\n", bh.Runlimit) + fmt.Printf("RefsCount: %d\n", bh.RefsCount) + fmt.Printf("TransactionsRoot: %x\n", bh.TransactionsRoot.Bytes()) + fmt.Printf("ContractsRoot: %x\n", bh.ContractsRoot.Bytes()) + fmt.Printf("NoncesRoot: %x\n", bh.NoncesRoot.Bytes()) + fmt.Printf("NextPredicate.Version: %d\n", bh.NextPredicate.Version) + fmt.Printf("NextPredicate.Quorum: %d\n", bh.NextPredicate.Quorum) + fmt.Printf("NextPredicate.Pubkeys: %s\n", strings.Join(pubkeys, " ")) + fmt.Printf("Transactions: %d\n", len(rb.Transactions)) + return nil + } + + headerBytes, err := proto.Marshal(rb.Header) + if err != nil { + return errors.Wrap(err, "serializing block header") + } + + _, err = os.Stdout.Write(headerBytes) + return errors.Wrap(err, "writing block header to stdout") +} + +func doNew(_ context.Context, quorum int, timeStr string, pubkeysHex []string) error { + var pubkeys []ed25519.PublicKey + for _, pubkeyHex := range pubkeysHex { + b, err := hex.DecodeString(pubkeyHex) + if err != nil { + return errors.Wrapf(err, "decoding pubkey %s", pubkeyHex) + } + if len(b) != ed25519.PublicKeySize { + return fmt.Errorf("bad pubkey length %d, want 32", len(b)) + } + pubkeys = append(pubkeys, ed25519.PublicKey(b)) + } + + if quorum < 0 || quorum > len(pubkeys) { + return fmt.Errorf("quorum must be between 1 and %d", len(pubkeys)) + } + if quorum == 0 { + // There may be zero pubkeys, in which case quorum will remain + // zero. But if there are any pubkeys then quorum should be at + // least 1. + quorum = len(pubkeys) + } + + var ts time.Time + if timeStr == "" { + ts = time.Now() + } else { + var err error + ts, err = time.Parse(time.RFC3339, timeStr) + if err != nil { + return errors.Wrap(err, "parsing timestamp") + } + } + + block, err := protocol.NewInitialBlock(pubkeys, quorum, ts) + if err != nil { + return errors.Wrap(err, "creating new block") + } + + blockBytes, err := block.Bytes() + if err != nil { + return errors.Wrap(err, "serializing block") + } + + _, err = os.Stdout.Write(blockBytes) + return errors.Wrap(err, "writing block to stdout") +} + +func doSign(_ context.Context, prevHex string, args []string) error { + prevBytes, err := hex.DecodeString(prevHex) + if err != nil { + return errors.Wrap(err, "decoding previous block header hex") + } + + var prev bc.BlockHeader + if err = proto.Unmarshal(prevBytes, &prev); err != nil { + return errors.Wrap(err, "parsing previous block header") + } + + blockBytes, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading block from stdin") + } + + block := new(bc.Block) + if err = block.FromBytes(blockBytes); err != nil { + return errors.Wrap(err, "parsing block") + } + + hash := block.Hash().Bytes() + + block, err = bc.SignBlock(block.UnsignedBlock, &prev, func(idx int) (interface{}, error) { + if idx >= len(args) { + return nil, nil + } + arg := args[idx] + if arg == "" { + return nil, nil + } + prv, err := hex.DecodeString(arg) + if err != nil { + return nil, errors.Wrapf(err, "decoding private key for signer %d", idx) + } + return ed25519.Sign(prv, hash), nil + }) + if err != nil { + return errors.Wrap(err, "signing block") + } + + blockBytes, err = block.Bytes() + if err != nil { + return errors.Wrap(err, "serializing signed block") + } + + _, err = os.Stdout.Write(blockBytes) + return errors.Wrap(err, "writing signed block to stdout") +} + +func doTx(_ context.Context, raw, pretty bool, idx int, _ []string) error { + if idx < 0 { + return fmt.Errorf("index out of range") + } + + inp, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading block from stdin") + } + + var rb bc.RawBlock + if err = proto.Unmarshal(inp, &rb); err != nil { + return errors.Wrap(err, "parsing raw block") + } + + if idx >= len(rb.Transactions) { + return fmt.Errorf("index out of range") + } + + tx := rb.Transactions[idx] + + if raw { + txBytes, err := proto.Marshal(tx) + if err != nil { + return errors.Wrap(err, "serializing raw transaction") + } + _, err = os.Stdout.Write(txBytes) + return errors.Wrap(err, "writing raw transaction to stdout") + } + + if pretty { + fmt.Printf("Version: %d\n", tx.Version) + fmt.Printf("Runlimit: %d\n", tx.Runlimit) + fmt.Printf("Program: %x\n", tx.Program) + return nil + } + + _, err = os.Stdout.Write(tx.Program) + return errors.Wrap(err, "writing transaction program to stdout") +} + +func doValidate(_ context.Context, prevHex string, noPrev, noSig bool, _ []string) error { + inp, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading block from stdin") + } + + var b bc.Block + if err = b.FromBytes(inp); err != nil { + return errors.Wrap(err, "parsing block") + } + + if prevHex != "" { + prevBytes, err := hex.DecodeString(prevHex) + if err != nil { + return errors.Wrap(err, "decoding previous block header hex") + } + + var prev bc.BlockHeader + if err = proto.Unmarshal(prevBytes, &prev); err != nil { + return errors.Wrap(err, "parsing previous block header") + } + + if err = validation.Block(b.UnsignedBlock, &prev); err != nil { + return errors.Wrap(err, "validating block") + } + + // TODO(bobg): consider a way to validate the ConsensusRoot and + // NoncesRoot too + + if noSig { + return nil + } + + err = validation.BlockSig(&b, prev.NextPredicate) + return errors.Wrap(err, "validating block signature") + } + + if b.Height == 1 || noPrev { + err = validation.BlockOnly(b.UnsignedBlock) + return errors.Wrap(err, "validating block") + } + + return fmt.Errorf("previous blockheader not supplied") +} diff --git a/cmd/internal/ed25519/ed25519.go b/cmd/internal/ed25519/ed25519.go new file mode 100644 index 0000000..0ddd07f --- /dev/null +++ b/cmd/internal/ed25519/ed25519.go @@ -0,0 +1,101 @@ +package ed25519 + +import ( + "context" + "encoding/hex" + "fmt" + "io" + "os" + + "github.com/bobg/subcmd/v2" + + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" +) + +func Run(ctx context.Context, args []string) error { + return subcmd.Run(ctx, cmd{}, args) +} + +type cmd struct{} + +func (c cmd) Subcmds() subcmd.Map { + return subcmd.Commands( + "gen", doGen, "generate a new private key", nil, + "pub", doPub, "derive public key from private key", nil, + "sign", doSign, "sign a message with a private key", subcmd.Params( + "prvhex", subcmd.String, "", "private key in hex", + ), + "verify", doVerify, "verify a signature with a public key", subcmd.Params( + "-s", subcmd.Bool, false, "silent mode", + "pubhex", subcmd.String, "", "public key in hex", + "sighex", subcmd.String, "", "signature in hex", + ), + ) +} + +func doGen(_ context.Context, _ []string) error { + _, prv, err := ed25519.GenerateKey(nil) + if err != nil { + return errors.Wrap(err, "generating key") + } + _, err = os.Stdout.Write(prv) + return errors.Wrap(err, "writing private key to stdout") +} + +func doPub(_ context.Context, _ []string) error { + prv, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading private key from stdin") + } + pub := ed25519.PrivateKey(prv).Public().(ed25519.PublicKey) + _, err = os.Stdout.Write([]byte(pub)) + return errors.Wrap(err, "writing public key to stdout") +} + +func doSign(_ context.Context, prvhex string, _ []string) error { + prv, err := hex.DecodeString(prvhex) + if err != nil { + return errors.Wrap(err, "decoding private key hex") + } + + msg, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading message from stdin") + } + + sig := ed25519.Sign(ed25519.PrivateKey(prv), msg) + _, err = os.Stdout.Write(sig) + return errors.Wrap(err, "writing signature to stdout") +} + +func doVerify(_ context.Context, silent bool, pubhex, sighex string, _ []string) error { + pub, err := hex.DecodeString(pubhex) + if err != nil { + return errors.Wrap(err, "decoding public key hex") + } + + sig, err := hex.DecodeString(sighex) + if err != nil { + return errors.Wrap(err, "decoding signature hex") + } + + msg, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading message from stdin") + } + + ok := ed25519.Verify(ed25519.PublicKey(pub), msg, sig) + if !silent { + if ok { + fmt.Println("OK") + } else { + fmt.Println("BAD") + } + } + if !ok { + os.Exit(1) + } + + return nil +} diff --git a/cmd/internal/hex/hex.go b/cmd/internal/hex/hex.go new file mode 100644 index 0000000..136cf5b --- /dev/null +++ b/cmd/internal/hex/hex.go @@ -0,0 +1,115 @@ +package hex + +import ( + "context" + "encoding/hex" + "io" + "os" + + "github.com/bobg/txvm/errors" +) + +func Run(_ context.Context, decode bool, lineLen int, _ []string) error { + if lineLen%2 != 0 { + lineLen-- + } + + var r io.Reader = &encodeReader{os.Stdin} + if lineLen >= 2 { + r = &splitLineReader{r: r, max: lineLen} + } + if decode { + r = &decodeReader{r: &stripSpaceReader{os.Stdin}} + } + + _, err := io.Copy(os.Stdout, r) + return errors.Wrap(err, "processing hex data") +} + +type encodeReader struct { + r io.Reader +} + +func (r *encodeReader) Read(p []byte) (int, error) { + if len(p)%2 == 1 { + p = p[:len(p)-1] + } + h := p[len(p)/2:] + n, err := r.r.Read(h) + return hex.Encode(p, h[:n]), err +} + +type splitLineReader struct { + r io.Reader + n int + max int +} + +func (r *splitLineReader) Read(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + p = p[:len(p)-1] // leave room for possible '\n' below + if len(p) > r.max-r.n { + p = p[:r.max-r.n] + } + n, err := r.r.Read(p) + p = p[:n] + r.n += n + if r.n >= r.max || err == io.EOF { + p = p[:n+1] + p[n] = '\n' + r.n = 0 + } + return len(p), err +} + +type decodeReader struct { + r io.Reader + par int // parity of last read (0 or 1) + b byte // odd byte from last read (if any) +} + +func (r *decodeReader) Read(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + if r.par == 1 { + p[0] = r.b + } + n, err := r.r.Read(p[r.par:]) + p = p[:r.par+n] + r.par = len(p) % 2 + if r.par == 1 { + r.b = p[len(p)-1] + p = p[:len(p)-1] + } + d, err1 := hex.Decode(p, p) + if err1 != nil { + return d, err1 + } + if r.par == 1 && err == io.EOF { + err = hex.ErrLength + } + return d, err +} + +type stripSpaceReader struct { + r io.Reader +} + +func (r *stripSpaceReader) Read(p []byte) (int, error) { + n, err := r.r.Read(p) + w := 0 + for _, b := range p[:n] { + if !isSpace(b) { + p[w] = b + w++ + } + } + return w, err +} + +func isSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' +} diff --git a/cmd/hex/main_test.go b/cmd/internal/hex/hex_test.go similarity index 74% rename from cmd/hex/main_test.go rename to cmd/internal/hex/hex_test.go index e31cb44..6289121 100644 --- a/cmd/hex/main_test.go +++ b/cmd/internal/hex/hex_test.go @@ -1,8 +1,8 @@ -package main +package hex import ( "bytes" - "io/ioutil" + "io" "strings" "testing" ) @@ -10,7 +10,7 @@ import ( func TestStripSpace(t *testing.T) { in := "a b c" - got, err := ioutil.ReadAll(&stripSpaceReader{strings.NewReader(in)}) + got, err := io.ReadAll(&stripSpaceReader{strings.NewReader(in)}) if err != nil { t.Fatal(err) } @@ -24,7 +24,7 @@ func TestStripSpace(t *testing.T) { func TestEncode(t *testing.T) { in := "\xab\xcd" - got, err := ioutil.ReadAll(&encodeReader{strings.NewReader(in)}) + got, err := io.ReadAll(&encodeReader{strings.NewReader(in)}) if err != nil { t.Fatal(err) } @@ -38,7 +38,7 @@ func TestEncode(t *testing.T) { func TestDecode(t *testing.T) { in := "abcd" - got, err := ioutil.ReadAll(&decodeReader{r: strings.NewReader(in)}) + got, err := io.ReadAll(&decodeReader{r: strings.NewReader(in)}) if err != nil { t.Fatal(err) } diff --git a/cmd/internal/tx/tx.go b/cmd/internal/tx/tx.go new file mode 100644 index 0000000..cc61cec --- /dev/null +++ b/cmd/internal/tx/tx.go @@ -0,0 +1,521 @@ +package tx + +import ( + "context" + "encoding/hex" + "flag" + "fmt" + "io" + "math" + "os" + "strings" + "time" + + "github.com/bobg/subcmd/v2" + "github.com/golang/protobuf/proto" + + "github.com/bobg/txvm/crypto/ed25519" + i10rjson "github.com/bobg/txvm/encoding/json" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txbuilder" + "github.com/bobg/txvm/protocol/txbuilder/txresult" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" +) + +func Run(ctx context.Context, args []string) error { + return subcmd.Run(ctx, cmd{}, args) +} + +type cmd struct{} + +func (c cmd) Subcmds() subcmd.Map { + wrv := subcmd.Params( + "-witness", subcmd.Bool, false, "expect a witness tuple on stdin", + "-runlimit", subcmd.Int64, math.MaxInt64, "runlimit", + "-version", subcmd.Int64, 3, "tx version", + ) + + return subcmd.Commands( + "build", doBuild, "create a transaction", subcmd.Params( + "-ttl", subcmd.Duration, time.Hour, "time-to-live as a Go duration string", + "-tags", subcmd.String, "", "hex or JSON-encoded set of transaction tags", + ), + "id", doID, "compute transaction ID", wrv, + "log", doLog, "emit transaction log", wrv, + "result", doResult, "decode transaction result", wrv, + "trace", doTrace, "trace transaction execution", wrv, + "validate", doValidate, "validate transaction", wrv, + ) +} + +func doBuild(ctx context.Context, ttl time.Duration, txtagsStr string, args []string) error { + var txtags []byte + if len(txtagsStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(txtagsStr)) + if err == nil { + txtags, _ = m.MarshalJSON() + } else { + txtags, err = hex.DecodeString(txtagsStr) + } + if err != nil { + return errors.Wrap(err, "decoding transaction tags") + } + } + + tpl := txbuilder.NewTemplate(time.Now().Add(ttl), txtags) + for len(args) > 0 { + var ( + fs flag.FlagSet + amount int64 + refdataStr string + ) + fs.Int64Var(&amount, "amount", 0, "amount") + fs.StringVar(&refdataStr, "refdata", "", "refdata (as hex or JSON object)") + + buildcmd := args[0] + args = args[1:] + + switch buildcmd { + case "issue": + var ( + version int + blockchainIDStr string + assetTagStr string + quorum int + prvStrs string + pubStrs string + nonceStr string + ) + fs.IntVar(&version, "version", 2, "asset contract version") + fs.StringVar(&blockchainIDStr, "blockchain", "", "blockchain ID (as hex)") + fs.StringVar(&assetTagStr, "tag", "", "asset tag (as hex or JSON object)") + fs.IntVar(&quorum, "quorum", 1, "quorum") + fs.StringVar(&prvStrs, "prv", "", "private keys (as hex, space-separated)") + fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") + fs.StringVar(&nonceStr, "nonce", "", "nonce (as hex)") + + if err := fs.Parse(args); err != nil { + return errors.Wrap(err, "parsing issue arguments") + } + + args = fs.Args() + + var refdata []byte + if len(refdataStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(refdataStr)) + if err == nil { + refdata, _ = m.MarshalJSON() + } else { + refdata, err = hex.DecodeString(refdataStr) + } + if err != nil { + return errors.Wrap(err, "decoding reference data") + } + } + + var ( + blockchainID []byte + assetTag []byte + prvs [][]byte + pubs []ed25519.PublicKey + nonce []byte + ) + if len(blockchainIDStr) > 0 { + var err error + blockchainID, err = hex.DecodeString(blockchainIDStr) + if err != nil { + return errors.Wrap(err, "decoding blockchain ID") + } + } + if len(assetTagStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(assetTagStr)) + if err == nil { + assetTag, _ = m.MarshalJSON() + } else { + assetTag, err = hex.DecodeString(assetTagStr) + } + if err != nil { + return errors.Wrap(err, "decoding asset tag") + } + } + for _, prvStr := range strings.Fields(prvStrs) { + prv, err := hex.DecodeString(prvStr) + if err != nil { + return errors.Wrap(err, "decoding private key") + } + prvs = append(prvs, prv) + } + for _, pubStr := range strings.Fields(pubStrs) { + pub, err := hex.DecodeString(pubStr) + if err != nil { + return errors.Wrap(err, "decoding public key") + } + pubs = append(pubs, ed25519.PublicKey(pub)) + } + if len(nonceStr) > 0 { + var err error + nonce, err = hex.DecodeString(nonceStr) + if err != nil { + return errors.Wrap(err, "decoding nonce") + } + } + tpl.AddIssuance(version, blockchainID, assetTag, quorum, prvs, nil, pubs, amount, refdata, nonce) + + case "input": + var ( + version int + quorum int + prvStrs string + pubStrs string + assetIDStr string + anchorStr string + ) + fs.IntVar(&version, "version", 2, "output [sic] contract version") + fs.IntVar(&quorum, "quorum", 1, "quorum") + fs.StringVar(&prvStrs, "prv", "", "private keys (as hex, space-separated)") + fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") + fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") + fs.StringVar(&anchorStr, "anchor", "", "anchor (as hex)") + + if err := fs.Parse(args); err != nil { + return errors.Wrap(err, "parsing input arguments") + } + + args = fs.Args() + + var refdata []byte + if len(refdataStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(refdataStr)) + if err == nil { + refdata, _ = m.MarshalJSON() + } else { + refdata, err = hex.DecodeString(refdataStr) + } + if err != nil { + return errors.Wrap(err, "decoding reference data") + } + } + + var ( + prvs [][]byte + pubs []ed25519.PublicKey + anchor []byte + assetID bc.Hash + ) + for prvStr := range strings.FieldsSeq(prvStrs) { + prv, err := hex.DecodeString(prvStr) + if err != nil { + return errors.Wrap(err, "decoding private key") + } + prvs = append(prvs, prv) + } + for pubStr := range strings.FieldsSeq(pubStrs) { + pub, err := hex.DecodeString(pubStr) + if err != nil { + return errors.Wrap(err, "decoding public key") + } + pubs = append(pubs, ed25519.PublicKey(pub)) + } + if err := assetID.UnmarshalText([]byte(assetIDStr)); err != nil { + return errors.Wrap(err, "decoding asset ID") + } + if len(anchorStr) > 0 { + var err error + anchor, err = hex.DecodeString(anchorStr) + if err != nil { + return errors.Wrap(err, "decoding anchor") + } + } + tpl.AddInput(quorum, prvs, nil, pubs, amount, assetID, anchor, refdata, version) + + case "output": + var ( + quorum int + pubStrs string + assetIDStr string + tagsStr string + ) + fs.IntVar(&quorum, "quorum", 1, "quorum") + fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") + fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") + fs.StringVar(&tagsStr, "tags", "", "tags (as hex or JSON object)") + + if err := fs.Parse(args); err != nil { + return errors.Wrap(err, "parsing output arguments") + } + + args = fs.Args() + + var refdata []byte + if len(refdataStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(refdataStr)) + if err == nil { + refdata, _ = m.MarshalJSON() + } else { + refdata, err = hex.DecodeString(refdataStr) + } + if err != nil { + return errors.Wrap(err, "decoding reference data") + } + } + + var ( + pubs []ed25519.PublicKey + assetID bc.Hash + tags []byte + ) + for _, pubStr := range strings.Fields(pubStrs) { + pub, err := hex.DecodeString(pubStr) + if err != nil { + return errors.Wrap(err, "decoding public key") + } + pubs = append(pubs, ed25519.PublicKey(pub)) + } + if err := assetID.UnmarshalText([]byte(assetIDStr)); err != nil { + return errors.Wrap(err, "decoding asset ID") + } + if len(tagsStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(tagsStr)) + if err == nil { + tags, _ = m.MarshalJSON() + } else { + tags, err = hex.DecodeString(tagsStr) + } + if err != nil { + return errors.Wrap(err, "decoding tags") + } + } + tpl.AddOutput(quorum, pubs, amount, assetID, refdata, tags) + + case "retire": + var assetIDStr string + fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") + + if err := fs.Parse(args); err != nil { + return errors.Wrap(err, "parsing retire arguments") + } + + args = fs.Args() + + var refdata []byte + if len(refdataStr) > 0 { + var m i10rjson.Map + err := m.UnmarshalJSON([]byte(refdataStr)) + if err == nil { + refdata, _ = m.MarshalJSON() + } else { + refdata, err = hex.DecodeString(refdataStr) + } + if err != nil { + return errors.Wrap(err, "decoding reference data") + } + } + + var assetID bc.Hash + if err := assetID.UnmarshalText([]byte(assetIDStr)); err != nil { + return errors.Wrap(err, "decoding asset ID") + } + + tpl.AddRetirement(amount, assetID, refdata) + } + } + + err := tpl.Sign(ctx, func(_ context.Context, msg []byte, prv []byte, _ [][]byte) ([]byte, error) { + return ed25519.Sign(prv, msg), nil + }) + if err != nil { + return errors.Wrap(err, "signing transaction") + } + + tx, err := tpl.Tx() + if err != nil { + return errors.Wrap(err, "building transaction") + } + + rawTx := &bc.RawTx{ + Version: tx.Version, + Runlimit: tx.Runlimit, + Program: tx.Program, + } + bits, err := proto.Marshal(rawTx) + if err != nil { + return errors.Wrap(err, "marshaling raw transaction") + } + _, err = os.Stdout.Write(bits) + return errors.Wrap(err, "writing raw transaction to stdout") +} + +func doID(_ context.Context, witness bool, runlimit, version int64, _ []string) error { + prog, err := getInp(witness, &runlimit, &version) + if err != nil { + return errors.Wrap(err, "getting input") + } + + vm, err := txvm.Validate(prog, version, runlimit, txvm.StopAfterFinalize) + if err != nil { + return errors.Wrap(err, "validating transaction") + } + if !vm.Finalized { + return txvm.ErrUnfinalized + } + + _, err = os.Stdout.Write(vm.TxID[:]) + return errors.Wrap(err, "writing transaction ID to stdout") +} + +func doLog(_ context.Context, witness bool, runlimit, version int64, _ []string) error { + prog, err := getInp(witness, &runlimit, &version) + if err != nil { + return errors.Wrap(err, "getting input") + } + + var innerErr error + _, err = txvm.Validate(prog, version, runlimit, txvm.StopAfterFinalize, txvm.OnFinalize(func(vm *txvm.VM) { + for _, tuple := range vm.Log { + dis, err := asm.Disassemble(txvm.Encode(tuple)) + if err != nil { + innerErr = errors.Wrap(err, "disassembling log entry") + return + } + fmt.Println(dis) + } + })) + if innerErr != nil { + return innerErr + } + return errors.Wrap(err, "processing transaction log") +} + +func doResult(_ context.Context, witness bool, runlimit, version int64, _ []string) error { + prog, err := getInp(witness, &runlimit, &version) + if err != nil { + return errors.Wrap(err, "getting input") + } + + tx, err := bc.NewTx(prog, version, runlimit) + if err != nil { + return errors.Wrap(err, "parsing transaction") + } + + result := txresult.New(tx) + + for i, iss := range tx.Issuances { + if i == 0 { + fmt.Println("Issuances:") + } + fmt.Printf(" assetID %x amount %d anchor %x", iss.AssetID.Bytes(), iss.Amount, iss.Anchor) + fmt.Printf(" seed %x program %x", iss.Seed.Bytes(), iss.Program) + if meta := result.Issuances[i]; meta != nil { + fmt.Printf(" refdata [%x] quorum %d pubkeys [", meta.RefData, meta.Quorum) + for i, p := range meta.Pubkeys { + if i > 0 { + fmt.Print(" ") + } + fmt.Printf("%x", []byte(p)) + } + fmt.Print("]") + } + fmt.Println() + } + + for i, ret := range tx.Retirements { + if i == 0 { + fmt.Println("Retirements:") + } + var refdata []byte + meta := result.Retirements[i] + if meta != nil { + refdata = meta.RefData + } + fmt.Printf(" assetID %x amount %d anchor %x refdata [%x]\n", ret.AssetID.Bytes(), ret.Amount, ret.Anchor, refdata) + } + + for i, inp := range tx.Inputs { + if i == 0 { + fmt.Println("Inputs:") + } + fmt.Printf(" contractID %x seed %x program %x", inp.ID.Bytes(), inp.Seed.Bytes(), inp.Program) + if meta := result.Inputs[i]; meta != nil { + fmt.Printf(" refdata [%x] quorum %d pubkeys [", meta.RefData, meta.Quorum) + for i, p := range meta.Pubkeys { + if i > 0 { + fmt.Print(" ") + } + fmt.Printf("%x", []byte(p)) + } + fmt.Print("]") + if value := meta.Value; value != nil { + fmt.Printf(" assetID %x amount %d anchor %x", value.AssetID.Bytes(), value.Amount, value.Anchor) + } + } + fmt.Println() + } + + for i, out := range tx.Outputs { + if i == 0 { + fmt.Println("Outputs:") + } + fmt.Printf(" contractID %x seed %x program %x", out.ID.Bytes(), out.Seed.Bytes(), out.Program) + if meta := result.Outputs[i]; meta != nil { + fmt.Printf(" refdata [%x] tokentags [%x] quorum %d pubkeys [", meta.RefData, meta.TokenTags, meta.Quorum) + for i, p := range meta.Pubkeys { + if i > 0 { + fmt.Print(" ") + } + fmt.Printf("%x", []byte(p)) + } + fmt.Print("]") + if value := meta.Value; value != nil { + fmt.Printf(" assetID %x amount %d anchor %x", value.AssetID.Bytes(), value.Amount, value.Anchor) + } + } + fmt.Println() + } + + return nil +} + +func doTrace(_ context.Context, witness bool, runlimit, version int64, _ []string) error { + prog, err := getInp(witness, &runlimit, &version) + if err != nil { + return errors.Wrap(err, "getting input") + } + + _, err = txvm.Validate(prog, version, runlimit, txvm.Trace(os.Stdout)) + return errors.Wrap(err, "tracing transaction execution") +} + +func doValidate(_ context.Context, witness bool, runlimit, version int64, _ []string) error { + prog, err := getInp(witness, &runlimit, &version) + if err != nil { + return errors.Wrap(err, "getting input") + } + + _, err = txvm.Validate(prog, version, runlimit) + return errors.Wrap(err, "validating transaction") +} + +func getInp(witness bool, runlimit, version *int64) ([]byte, error) { + prog, err := io.ReadAll(os.Stdin) + if err != nil { + return nil, errors.Wrap(err, "reading stdin") + } + + if witness { + var rawTx bc.RawTx + if err := proto.Unmarshal(prog, &rawTx); err != nil { + return nil, errors.Wrap(err, "unmarshaling raw transaction") + } + *runlimit, *version, prog = rawTx.Runlimit, rawTx.Version, rawTx.Program + } + + return prog, nil +} diff --git a/cmd/internal/vmhash/vmhash.go b/cmd/internal/vmhash/vmhash.go new file mode 100644 index 0000000..a1637d3 --- /dev/null +++ b/cmd/internal/vmhash/vmhash.go @@ -0,0 +1,20 @@ +package vmhash + +import ( + "context" + "io" + "os" + + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" +) + +func Run(_ context.Context, funcname string, _ []string) error { + inp, err := io.ReadAll(os.Stdin) + if err != nil { + return errors.Wrap(err, "reading stdin") + } + h := txvm.VMHash(funcname, inp) + _, err = os.Stdout.Write(h[:]) + return errors.Wrap(err, "writing stdout") +} diff --git a/cmd/tx/doc.go b/cmd/tx/doc.go index 0109e07..944f909 100644 --- a/cmd/tx/doc.go +++ b/cmd/tx/doc.go @@ -1,5 +1,4 @@ /* - Command tx parses and operates on Chain protocol transactions and performs various operations on them. @@ -47,42 +46,41 @@ specifies a hex- or JSON-encoded set of tags for the transaction. Each directive has its own set of arguments: - issue: - -version V integer version of the asset contract to use - -blockchain HEX hex-encoded blockchain ID for unanchored issuances - -tag TAG hex- or JSON-encoded asset tag - -quorum N integer quorum - -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -refdata D hex- or JSON-encoded reference data - -nonce HEX hex-encoded issuance nonce - - input: - -quorum N integer quorum - -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -anchor HEX hex-encoded anchor - -refdata D hex- or JSON-encoded reference data - -version V integer version of the output [sic] contract to use - - output: - -quorum N integer quorum - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -refdata D hex- or JSON-encoded reference data - -tags T hex- or JSON-encoded tags - - retire: - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -refdata D hex- or JSON-encoded reference data + issue: + -version V integer version of the asset contract to use + -blockchain HEX hex-encoded blockchain ID for unanchored issuances + -tag TAG hex- or JSON-encoded asset tag + -quorum N integer quorum + -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing + -pub 'P1 P2 ...' hex-encoded, space-separated public keys + -amount N integer amount to issue + -refdata D hex- or JSON-encoded reference data + -nonce HEX hex-encoded issuance nonce + + input: + -quorum N integer quorum + -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing + -pub 'P1 P2 ...' hex-encoded, space-separated public keys + -amount N integer amount to issue + -assetid HEX hex-encoded asset ID + -anchor HEX hex-encoded anchor + -refdata D hex- or JSON-encoded reference data + -version V integer version of the output [sic] contract to use + + output: + -quorum N integer quorum + -pub 'P1 P2 ...' hex-encoded, space-separated public keys + -amount N integer amount to issue + -assetid HEX hex-encoded asset ID + -refdata D hex- or JSON-encoded reference data + -tags T hex- or JSON-encoded tags + + retire: + -amount N integer amount to issue + -assetid HEX hex-encoded asset ID + -refdata D hex- or JSON-encoded reference data See example.md for an extended example of creating realistic blockchain data. - */ package main diff --git a/cmd/tx/main.go b/cmd/tx/main.go index 29426cc..4bcea3c 100644 --- a/cmd/tx/main.go +++ b/cmd/tx/main.go @@ -2,514 +2,19 @@ package main import ( "context" - "encoding/hex" - "flag" "fmt" - "io/ioutil" - "math" "os" - "strings" - "time" - "github.com/golang/protobuf/proto" - - "github.com/chain/txvm/crypto/ed25519" - i10rjson "github.com/chain/txvm/encoding/json" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txbuilder" - "github.com/chain/txvm/protocol/txbuilder/txresult" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/cmd/internal/tx" ) -var args []string - func main() { - if len(os.Args) < 2 { - usage() - } - subcommand := os.Args[1] - args = os.Args[2:] - - switch subcommand { - case "id": - prog, version, runlimit := getWitness() - vm, err := txvm.Validate(prog, version, runlimit, txvm.StopAfterFinalize) - must(err) - if !vm.Finalized { - panic(txvm.ErrUnfinalized) - } - os.Stdout.Write(vm.TxID[:]) - - case "validate": - prog, version, runlimit := getWitness() - _, err := txvm.Validate(prog, version, runlimit) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - - case "trace": - prog, version, runlimit := getWitness() - txvm.Validate(prog, version, runlimit, txvm.Trace(os.Stdout)) - - case "log": - prog, version, runlimit := getWitness() - _, err := txvm.Validate(prog, version, runlimit, txvm.StopAfterFinalize, txvm.OnFinalize(func(vm *txvm.VM) { - for _, tuple := range vm.Log { - dis, err := asm.Disassemble(txvm.Encode(tuple)) - must(err) - fmt.Println(dis) - } - })) - must(err) - - case "result": - prog, version, runlimit := getWitness() - tx, err := bc.NewTx(prog, version, runlimit) - must(err) - result := txresult.New(tx) - for i, iss := range tx.Issuances { - if i == 0 { - fmt.Println("Issuances:") - } - fmt.Printf(" assetID %x amount %d anchor %x", iss.AssetID.Bytes(), iss.Amount, iss.Anchor) - fmt.Printf(" seed %x program %x", iss.Seed.Bytes(), iss.Program) - if meta := result.Issuances[i]; meta != nil { - fmt.Printf(" refdata [%x] quorum %d pubkeys [", meta.RefData, meta.Quorum) - for i, p := range meta.Pubkeys { - if i > 0 { - fmt.Print(" ") - } - fmt.Printf("%x", []byte(p)) - } - fmt.Print("]") - } - fmt.Println() - } - for i, ret := range tx.Retirements { - if i == 0 { - fmt.Println("Retirements:") - } - var refdata []byte - meta := result.Retirements[i] - if meta != nil { - refdata = meta.RefData - } - fmt.Printf(" assetID %x amount %d anchor %x refdata [%x]\n", ret.AssetID.Bytes(), ret.Amount, ret.Anchor, refdata) - } - for i, inp := range tx.Inputs { - if i == 0 { - fmt.Println("Inputs:") - } - fmt.Printf(" contractID %x seed %x program %x", inp.ID.Bytes(), inp.Seed.Bytes(), inp.Program) - if meta := result.Inputs[i]; meta != nil { - fmt.Printf(" refdata [%x] quorum %d pubkeys [", meta.RefData, meta.Quorum) - for i, p := range meta.Pubkeys { - if i > 0 { - fmt.Print(" ") - } - fmt.Printf("%x", []byte(p)) - } - fmt.Print("]") - if value := meta.Value; value != nil { - fmt.Printf(" assetID %x amount %d anchor %x", value.AssetID.Bytes(), value.Amount, value.Anchor) - } - } - fmt.Println() - } - for i, out := range tx.Outputs { - if i == 0 { - fmt.Println("Outputs:") - } - fmt.Printf(" contractID %x seed %x program %x", out.ID.Bytes(), out.Seed.Bytes(), out.Program) - if meta := result.Outputs[i]; meta != nil { - fmt.Printf(" refdata [%x] tokentags [%x] quorum %d pubkeys [", meta.RefData, meta.TokenTags, meta.Quorum) - for i, p := range meta.Pubkeys { - if i > 0 { - fmt.Print(" ") - } - fmt.Printf("%x", []byte(p)) - } - fmt.Print("]") - if value := meta.Value; value != nil { - fmt.Printf(" assetID %x amount %d anchor %x", value.AssetID.Bytes(), value.Amount, value.Anchor) - } - } - fmt.Println() - } - - case "build": - var ( - txfs flag.FlagSet - ttl time.Duration - txtagsStr string - ) - txfs.DurationVar(&ttl, "ttl", time.Hour, "ttl") - txfs.StringVar(&txtagsStr, "tags", "", "tx tags (as hex or JSON object)") - - err := txfs.Parse(args) - must(err) - args = txfs.Args() - var txtags []byte - if len(txtagsStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(txtagsStr)) - if err == nil { - txtags, _ = m.MarshalJSON() - } else { - txtags, err = hex.DecodeString(txtagsStr) - } - must(err) - } - - tpl := txbuilder.NewTemplate(time.Now().Add(ttl), txtags) - for len(args) > 0 { - var ( - fs flag.FlagSet - amount int64 - refdataStr string - ) - fs.Int64Var(&amount, "amount", 0, "amount") - fs.StringVar(&refdataStr, "refdata", "", "refdata (as hex or JSON object)") - - buildcmd := args[0] - args = args[1:] - - switch buildcmd { - case "issue": - var ( - version int - blockchainIDStr string - assetTagStr string - quorum int - prvStrs string - pubStrs string - nonceStr string - ) - fs.IntVar(&version, "version", 2, "asset contract version") - fs.StringVar(&blockchainIDStr, "blockchain", "", "blockchain ID (as hex)") - fs.StringVar(&assetTagStr, "tag", "", "asset tag (as hex or JSON object)") - fs.IntVar(&quorum, "quorum", 1, "quorum") - fs.StringVar(&prvStrs, "prv", "", "private keys (as hex, space-separated)") - fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") - fs.StringVar(&nonceStr, "nonce", "", "nonce (as hex)") - - err = fs.Parse(args) - must(err) - args = fs.Args() - var refdata []byte - if len(refdataStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(refdataStr)) - if err == nil { - refdata, _ = m.MarshalJSON() - } else { - refdata, err = hex.DecodeString(refdataStr) - } - must(err) - } - - var ( - blockchainID []byte - assetTag []byte - prvs [][]byte - pubs []ed25519.PublicKey - nonce []byte - ) - if len(blockchainIDStr) > 0 { - blockchainID, err = hex.DecodeString(blockchainIDStr) - must(err) - } - if len(assetTagStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(assetTagStr)) - if err == nil { - assetTag, _ = m.MarshalJSON() - } else { - assetTag, err = hex.DecodeString(assetTagStr) - } - must(err) - } - for _, prvStr := range strings.Fields(prvStrs) { - prv, err := hex.DecodeString(prvStr) - must(err) - prvs = append(prvs, prv) - } - for _, pubStr := range strings.Fields(pubStrs) { - pub, err := hex.DecodeString(pubStr) - must(err) - pubs = append(pubs, ed25519.PublicKey(pub)) - } - if len(nonceStr) > 0 { - nonce, err = hex.DecodeString(nonceStr) - must(err) - } - tpl.AddIssuance(version, blockchainID, assetTag, quorum, prvs, nil, pubs, amount, refdata, nonce) - - case "input": - var ( - version int - quorum int - prvStrs string - pubStrs string - assetIDStr string - anchorStr string - ) - fs.IntVar(&version, "version", 2, "output [sic] contract version") - fs.IntVar(&quorum, "quorum", 1, "quorum") - fs.StringVar(&prvStrs, "prv", "", "private keys (as hex, space-separated)") - fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") - fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") - fs.StringVar(&anchorStr, "anchor", "", "anchor (as hex)") - - err = fs.Parse(args) - must(err) - args = fs.Args() - var refdata []byte - if len(refdataStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(refdataStr)) - if err == nil { - refdata, _ = m.MarshalJSON() - } else { - refdata, err = hex.DecodeString(refdataStr) - } - must(err) - } - - var ( - prvs [][]byte - pubs []ed25519.PublicKey - anchor []byte - assetID bc.Hash - ) - for _, prvStr := range strings.Fields(prvStrs) { - prv, err := hex.DecodeString(prvStr) - must(err) - prvs = append(prvs, prv) - } - for _, pubStr := range strings.Fields(pubStrs) { - pub, err := hex.DecodeString(pubStr) - must(err) - pubs = append(pubs, ed25519.PublicKey(pub)) - } - err = assetID.UnmarshalText([]byte(assetIDStr)) - must(err) - if len(anchorStr) > 0 { - anchor, err = hex.DecodeString(anchorStr) - must(err) - } - tpl.AddInput(quorum, prvs, nil, pubs, amount, assetID, anchor, refdata, version) - - case "output": - var ( - quorum int - pubStrs string - assetIDStr string - tagsStr string - ) - fs.IntVar(&quorum, "quorum", 1, "quorum") - fs.StringVar(&pubStrs, "pub", "", "public keys (as hex, space-separated)") - fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") - fs.StringVar(&tagsStr, "tags", "", "tags (as hex or JSON object)") - - err = fs.Parse(args) - must(err) - args = fs.Args() - var refdata []byte - if len(refdataStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(refdataStr)) - if err == nil { - refdata, _ = m.MarshalJSON() - } else { - refdata, err = hex.DecodeString(refdataStr) - } - must(err) - } - - var ( - pubs []ed25519.PublicKey - assetID bc.Hash - tags []byte - ) - for _, pubStr := range strings.Fields(pubStrs) { - pub, err := hex.DecodeString(pubStr) - must(err) - pubs = append(pubs, ed25519.PublicKey(pub)) - } - err = assetID.UnmarshalText([]byte(assetIDStr)) - must(err) - if len(tagsStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(tagsStr)) - if err == nil { - tags, _ = m.MarshalJSON() - } else { - tags, err = hex.DecodeString(tagsStr) - } - must(err) - } - tpl.AddOutput(quorum, pubs, amount, assetID, refdata, tags) - - case "retire": - var assetIDStr string - fs.StringVar(&assetIDStr, "assetid", "", "asset ID (as hex)") - - err = fs.Parse(args) - must(err) - args = fs.Args() - var refdata []byte - if len(refdataStr) > 0 { - var m i10rjson.Map - err = m.UnmarshalJSON([]byte(refdataStr)) - if err == nil { - refdata, _ = m.MarshalJSON() - } else { - refdata, err = hex.DecodeString(refdataStr) - } - must(err) - } - - var assetID bc.Hash - err = assetID.UnmarshalText([]byte(assetIDStr)) - must(err) - - tpl.AddRetirement(amount, assetID, refdata) - } - } - err = tpl.Sign(context.Background(), func(_ context.Context, msg []byte, prv []byte, _ [][]byte) ([]byte, error) { - return ed25519.Sign(prv, msg), nil - }) - must(err) - tx, err := tpl.Tx() - must(err) - rawTx := &bc.RawTx{ - Version: tx.Version, - Runlimit: tx.Runlimit, - Program: tx.Program, - } - bits, err := proto.Marshal(rawTx) - must(err) - os.Stdout.Write(bits) - - default: - usage() + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(1) } } -func getWitness() (prog []byte, version, runlimit int64) { - var fs flag.FlagSet - witness := fs.Bool("witness", false, "expect a witness tuple on stdin") - fs.Int64Var(&runlimit, "runlimit", math.MaxInt64, "runlimit") - fs.Int64Var(&version, "version", 3, "tx version") - err := fs.Parse(args) - must(err) - args = fs.Args() - - inp, err := ioutil.ReadAll(os.Stdin) - must(err) - - if *witness { - var rawTx bc.RawTx - err = proto.Unmarshal(inp, &rawTx) - must(err) - - runlimit = rawTx.Runlimit - version = rawTx.Version - prog = rawTx.Program - } else { - prog = inp - } - - return prog, version, runlimit -} - -func usage() { - fmt.Fprint(os.Stderr, `Usage: - - tx SUBCOMMAND ...args... - -Available subcommands are: id, validate, trace, log, result, build. - -All subcommands except build expect a transaction program on standard -input, assigning it a default version of 3 and a default runlimit of -2^63-1. The -runlimit and -version flags can override those default -values. These subcommands also accept a -witness flag tells tx to -expect a transaction witness tuple on standard input instead (such as -can be produced with the "block tx -raw" command, qv), which dictates -the version and runlimit. - -The id subcommand causes tx to compute the transaction's ID and send -it to standard output. Errors in the transaction beyond the "finalize" -instruction are not detected. - -The validate subcommand causes tx to validate the transaction. Exit -value 0 means the transaction is valid, non-zero means it is not. - -The trace subcommand causes an execution trace of the tx to be sent to -standard output. - -The log subcommand causes the transaction's log entries to be sent to -standard output in assembly-language syntax, one per line. Errors in -the transaction beyond the "finalize" instruction are not detected. - -The result subcommand parses the transaction log for information -produced by "standard" issuance, retirement, input, and output -contracts and prints the information in human-readable form. - -The build subcommand creates a transaction. It is used like this: - - tx build [-ttl TIME] [-tags TAGS] DIRECTIVE ...args... DIRECTIVE ...args... - -where each DIRECTIVE is one of "issue," "input," "output," and -"retire." Each directive adds an entry to the transaction being -built. The -ttl flag specifies the transaction's time to live; its -format must be understood by Go's time.ParseDuration. The -tags flag -specifies a hex- or JSON-encoded set of tags for the transaction. - -Each directive has its own set of arguments: - - issue: - -version V integer version of the asset contract to use - -blockchain HEX hex-encoded blockchain ID for unanchored issuances - -tag TAG hex- or JSON-encoded asset tag - -quorum N integer quorum - -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -refdata D hex- or JSON-encoded reference data - -nonce HEX hex-encoded issuance nonce - - input: - -quorum N integer quorum - -prv 'S1 S2 ...' hex-encoded, space-separated private keys for signing - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -anchor HEX hex-encoded anchor - -refdata D hex- or JSON-encoded reference data - -version V integer version of the output [sic] contract to use - - output: - -quorum N integer quorum - -pub 'P1 P2 ...' hex-encoded, space-separated public keys - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -refdata D hex- or JSON-encoded reference data - -tags T hex- or JSON-encoded tags - - retire: - -amount N integer amount to issue - -assetid HEX hex-encoded asset ID - -refdata D hex- or JSON-encoded reference data -`) - os.Exit(1) -} - -func must(err error) { - if err != nil { - panic(err) - } +func run() error { + return tx.Run(context.Background(), os.Args[1:]) } diff --git a/cmd/txvm/main.go b/cmd/txvm/main.go new file mode 100644 index 0000000..a156d72 --- /dev/null +++ b/cmd/txvm/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "context" + "fmt" + "math" + "os" + + "github.com/bobg/subcmd/v2" + + "github.com/bobg/txvm/cmd/internal/asm" + "github.com/bobg/txvm/cmd/internal/assetid" + "github.com/bobg/txvm/cmd/internal/bcstate" + "github.com/bobg/txvm/cmd/internal/block" + "github.com/bobg/txvm/cmd/internal/ed25519" + "github.com/bobg/txvm/cmd/internal/hex" + "github.com/bobg/txvm/cmd/internal/tx" + "github.com/bobg/txvm/cmd/internal/vmhash" +) + +func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } +} + +func run() error { + return subcmd.Run(context.Background(), maincmd{}, os.Args[1:]) +} + +type maincmd struct{} + +func (m maincmd) Subcmds() subcmd.Map { + return subcmd.Commands( + "asm", asm.Run, "assemble or disassemble txvm bytecode", subcmd.Params( + "-d", subcmd.Bool, false, "disassemble", + ), + "assetid", assetid.Run, "compute txvm asset ID", subcmd.Params( + "-t", subcmd.String, "", "hex asset tag", + "-v", subcmd.Int, 2, "asset contract version", + "quorum", subcmd.Int, 0, "number of required signatures", + ), + "bcstate", bcstate.Run, "read/write blockchain state", subcmd.Params( + "-block", subcmd.String, "", "file containing block to apply to state", + "-state", subcmd.String, "", "file containing initial state (default empty)", + ), + "block", block.Run, "manipulate txvm blocks", nil, + "ed25519", ed25519.Run, "create and manipulate ed25519 keys", nil, + "hex", hex.Run, "encode or decode hex", subcmd.Params( + "-d", subcmd.Bool, false, "decode", + "-n", subcmd.Int, math.MaxInt32, "number of bytes per line for encoding", + ), + "tx", tx.Run, "parse and operate on txvm transactions", nil, + "vmhash", vmhash.Run, "compute txvm VM hash of transactions", subcmd.Params( + "funcname", subcmd.String, "", "name of function to apply to the input", + ), + ) +} diff --git a/cmd/vmhash/doc.go b/cmd/vmhash/doc.go index dfd71e5..28a3c7c 100644 --- a/cmd/vmhash/doc.go +++ b/cmd/vmhash/doc.go @@ -1,5 +1,4 @@ /* - Command vmhash computes the vmhash of some input and a given "function name." Usage: @@ -8,8 +7,7 @@ Usage: Example: - $ echo "" | vmhash 'tag' | hex - 5eb2259cfc1552b797f4cf5dc1e7cb5c6891fe5255e314c2041697bca25b14a5 - + $ echo "" | vmhash 'tag' | hex + 5eb2259cfc1552b797f4cf5dc1e7cb5c6891fe5255e314c2041697bca25b14a5 */ package main diff --git a/cmd/vmhash/vmhash.go b/cmd/vmhash/vmhash.go index 6b45490..a42f785 100644 --- a/cmd/vmhash/vmhash.go +++ b/cmd/vmhash/vmhash.go @@ -1,25 +1,23 @@ package main import ( - "io/ioutil" + "context" + "fmt" "os" - "github.com/chain/txvm/protocol/txvm" + "github.com/bobg/txvm/cmd/internal/vmhash" ) func main() { - if len(os.Args) < 2 { - panic("usage: vmhash funcname > 5) @@ -1448,11 +1463,13 @@ func ScMulAdd(s, a, b, c *[32]byte) { } // Input: -// s[0]+256*s[1]+...+256^63*s[63] = s +// +// s[0]+256*s[1]+...+256^63*s[63] = s // // Output: -// s[0]+256*s[1]+...+256^31*s[31] = s mod l -// where l = 2^252 + 27742317777372353535851937790883648493. +// +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. func ScReduce(out *[32]byte, s *[64]byte) { s0 := 2097151 & load3(s[:]) s1 := 2097151 & (load4(s[2:]) >> 5) diff --git a/crypto/ed25519/json.go b/crypto/ed25519/json.go index 7373d43..0eb6baf 100644 --- a/crypto/ed25519/json.go +++ b/crypto/ed25519/json.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" - i10rjson "github.com/chain/txvm/encoding/json" + i10rjson "github.com/bobg/txvm/encoding/json" ) // UnmarshalJSON satisfies the json.Unmarshaler interface. diff --git a/crypto/sha3/doc.go b/crypto/sha3/doc.go index 3dab530..fed02ae 100644 --- a/crypto/sha3/doc.go +++ b/crypto/sha3/doc.go @@ -8,8 +8,7 @@ // Both types of hash function use the "sponge" construction and the Keccak // permutation. For a detailed specification see http://keccak.noekeon.org/ // -// -// Guidance +// # Guidance // // If you aren't sure what function you need, use SHAKE256 with at least 64 // bytes of output. The SHAKE instances are faster than the SHA3 instances; @@ -19,8 +18,7 @@ // secret key to the input, hash with SHAKE256 and read at least 32 bytes of // output. // -// -// Security strengths +// # Security strengths // // The SHA3-x (x equals 224, 256, 384, or 512) functions have a security // strength against preimage attacks of x bits. Since they only produce "x" @@ -31,8 +29,7 @@ // is used. Requesting more than 64 or 32 bytes of output, respectively, does // not increase the collision-resistance of the SHAKE functions. // -// -// The sponge construction +// # The sponge construction // // A sponge builds a pseudo-random function from a public pseudo-random // permutation, by applying the permutation to a state of "rate + capacity" @@ -50,8 +47,7 @@ // Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means // that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. // -// -// Recommendations +// # Recommendations // // The SHAKE functions are recommended for most new uses. They can produce // output of arbitrary length. SHAKE256, with an output length of at least diff --git a/crypto/sha3/keccakf.go b/crypto/sha3/keccakf.go index 46d03ed..8a3fe26 100644 --- a/crypto/sha3/keccakf.go +++ b/crypto/sha3/keccakf.go @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 appengine gccgo +//go:build !amd64 || appengine || gccgo +// +build !amd64 appengine gccgo package sha3 diff --git a/crypto/sha3/keccakf_amd64.go b/crypto/sha3/keccakf_amd64.go index de035c5..c0cfd17 100644 --- a/crypto/sha3/keccakf_amd64.go +++ b/crypto/sha3/keccakf_amd64.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build amd64 && !appengine && !gccgo // +build amd64,!appengine,!gccgo package sha3 diff --git a/crypto/sha3/register.go b/crypto/sha3/register.go index 3cf6a22..8b4453a 100644 --- a/crypto/sha3/register.go +++ b/crypto/sha3/register.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.4 // +build go1.4 package sha3 diff --git a/crypto/sha3/sha3_test.go b/crypto/sha3/sha3_test.go index 312e8f9..712456f 100644 --- a/crypto/sha3/sha3_test.go +++ b/crypto/sha3/sha3_test.go @@ -54,15 +54,6 @@ var testShakes = map[string]func() ShakeHash{ "SHAKE256": NewShake256, } -// decodeHex converts a hex-encoded string into a raw byte string. -func decodeHex(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} - // structs used to marshal JSON test-cases. type KeccakKats struct { Kats map[string][]struct { @@ -124,37 +115,6 @@ func TestKeccakKats(t *testing.T) { }) } -// TestUnalignedWrite tests that writing data in an arbitrary pattern with -// small input buffers. -func testUnalignedWrite(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - buf := sequentialBytes(0x10000) - for alg, df := range testDigests { - d := df() - d.Reset() - d.Write(buf) - want := d.Sum(nil) - d.Reset() - for i := 0; i < len(buf); { - // Cycle through offsets which make a 137 byte sequence. - // Because 137 is prime this sequence should exercise all corner cases. - offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1} - for _, j := range offsets { - if v := len(buf) - i; v < j { - j = v - } - d.Write(buf[i : i+j]) - i += j - } - } - got := d.Sum(nil) - if !bytes.Equal(got, want) { - t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) - } - } - }) -} - // TestAppend checks that appending works when reallocation is necessary. func TestAppend(t *testing.T) { testUnalignedAndGeneric(t, func(impl string) { @@ -202,7 +162,7 @@ func TestSqueezing(t *testing.T) { d1 := newShakeHash() d1.Write([]byte(testString)) var multiple []byte - for _ = range ref { + for range ref { one := make([]byte, 1) d1.Read(one) multiple = append(multiple, one...) diff --git a/crypto/sha3/xor.go b/crypto/sha3/xor.go index 46a0d63..1d88b11 100644 --- a/crypto/sha3/xor.go +++ b/crypto/sha3/xor.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (!amd64 && !386 && !ppc64le) || appengine // +build !amd64,!386,!ppc64le appengine package sha3 diff --git a/crypto/sha3/xor_unaligned.go b/crypto/sha3/xor_unaligned.go index 929a486..47a04fb 100644 --- a/crypto/sha3/xor_unaligned.go +++ b/crypto/sha3/xor_unaligned.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build (amd64 || 386 || ppc64le) && !appengine // +build amd64 386 ppc64le // +build !appengine diff --git a/crypto/sha3pool/pool.go b/crypto/sha3pool/pool.go index 8de12fc..a0945c2 100644 --- a/crypto/sha3pool/pool.go +++ b/crypto/sha3pool/pool.go @@ -4,7 +4,7 @@ package sha3pool import ( "sync" - "github.com/chain/txvm/crypto/sha3" + "github.com/bobg/txvm/crypto/sha3" ) var pool = &sync.Pool{New: func() interface{} { return sha3.New256() }} diff --git a/errors/doc.go b/errors/doc.go index 2c26938..5cc1f95 100644 --- a/errors/doc.go +++ b/errors/doc.go @@ -33,7 +33,7 @@ Example: log.Println("success") } -When to wrap errors +# When to wrap errors Errors should be wrapped with additional messages when the context is ambiguous. This includes when the error could arise in multiple locations in the same @@ -41,7 +41,7 @@ function, when the error is very common and likely to appear at different points in the call tree (e.g., JSON serialization errors), or when you need specific parameters alongside the original error message. -Error handling best practices +# Error handling best practices Errors are part of a function's interface. If you expect the caller to perform conditional error handling, you should document the errors returned by your diff --git a/errors/errors.go b/errors/errors.go index 4aeddbf..22657b7 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -138,7 +138,9 @@ func withData(err error, v map[string]interface{}) error { // The map contains the values in the map in err, // if any, plus the items in keyval. // Keyval takes the form -// k1, v1, k2, v2, ... +// +// k1, v1, k2, v2, ... +// // Values kN must be strings. // Calling Data on the returned error yields the map. // Note that if err already has a data item of any other type, diff --git a/errors/example_test.go b/errors/example_test.go index b49e018..0704e18 100644 --- a/errors/example_test.go +++ b/errors/example_test.go @@ -1,6 +1,6 @@ package errors_test -import "github.com/chain/txvm/errors" +import "github.com/bobg/txvm/errors" var ErrInvalidKey = errors.New("invalid key") diff --git a/go.mod b/go.mod index d1abc5c..afed31c 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,6 @@ -module github.com/chain/txvm +module github.com/bobg/txvm + +go 1.25.3 require ( github.com/davecgh/go-spew v1.1.1 @@ -6,3 +8,8 @@ require ( github.com/miscreant/miscreant v0.3.0 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 ) + +require ( + github.com/bobg/subcmd/v2 v2.3.0 // indirect + github.com/pkg/errors v0.9.1 // indirect +) diff --git a/go.sum b/go.sum index 226ecdc..bbb7c06 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,14 @@ +github.com/bobg/subcmd/v2 v2.3.0 h1:7Pq4GUN4jYwkOguz1a64r6gyVxQpNoqegAquG9CG8wQ= +github.com/bobg/subcmd/v2 v2.3.0/go.mod h1:fjEpI7mfn8eXEoQ7+lx+dA22sebrbrIa1VMzplZzjpE= 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/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/miscreant/miscreant v0.3.0 h1:bCn4zQMvNeeFBE3PWrG9ePFLPZyttBPhJ/WDqyqWrLQ= github.com/miscreant/miscreant v0.3.0/go.mod h1:ZKWeIKfbJej2zjb1OUXJaaP1DnCb4yoTtcR90O7BOD4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/log/log.go b/log/log.go index 98b28d2..a7b1aba 100644 --- a/log/log.go +++ b/log/log.go @@ -13,7 +13,7 @@ import ( "strings" "sync" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) // context key type diff --git a/log/log_test.go b/log/log_test.go index 520c86e..258504e 100644 --- a/log/log_test.go +++ b/log/log_test.go @@ -3,19 +3,19 @@ package log import ( "bytes" "context" - "io/ioutil" + "io" "os" "reflect" "runtime" "strings" "testing" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) func TestSetOutput(t *testing.T) { var buf bytes.Buffer - want := "foobar" + const want = "foobar" SetOutput(&buf) Printf(context.Background(), want) SetOutput(os.Stdout) @@ -158,7 +158,7 @@ func TestPrintkv(t *testing.T) { Printkv(context.Background(), ex.keyvals...) - read, err := ioutil.ReadAll(buf) + read, err := io.ReadAll(buf) if err != nil { SetOutput(os.Stdout) t.Fatal("read buffer error:", err) @@ -186,7 +186,7 @@ func TestMessagef(t *testing.T) { Printf(context.Background(), "test round %d", 0) - read, err := ioutil.ReadAll(buf) + read, err := io.ReadAll(buf) if err != nil { t.Fatal("read buffer error:", err) } @@ -213,7 +213,7 @@ func TestPrintkvStack(t *testing.T) { wrapped := errors.Wrap(root) Printkv(context.Background(), KeyError, wrapped) - read, err := ioutil.ReadAll(buf) + read, err := io.ReadAll(buf) if err != nil { t.Fatal("read buffer error:", err) } @@ -245,7 +245,7 @@ func TestError(t *testing.T) { wrapped := errors.Wrap(root) Error(context.Background(), wrapped, "failure x ", 0) - read, err := ioutil.ReadAll(buf) + read, err := io.ReadAll(buf) if err != nil { t.Fatal("read buffer error:", err) } @@ -290,7 +290,7 @@ func TestHelperStack(t *testing.T) { Error(context.Background(), errors.New("boo"), "failure x ", 0) - read, err := ioutil.ReadAll(buf) + read, err := io.ReadAll(buf) if err != nil { t.Fatal("read buffer error:", err) } diff --git a/log/rotation/file.go b/log/rotation/file.go index 4e14a10..833f948 100644 --- a/log/rotation/file.go +++ b/log/rotation/file.go @@ -3,6 +3,7 @@ package rotation import ( "bytes" + "io" "os" "strconv" ) @@ -87,7 +88,7 @@ func (f *File) write(p []byte) (int, error) { if err != nil { return 0, err } - f.w, err = f.f.Seek(0, os.SEEK_END) + f.w, err = f.f.Seek(0, io.SeekEnd) if err != nil { return 0, err } diff --git a/log/rotation/file_test.go b/log/rotation/file_test.go index b751c2b..b3e7c4d 100644 --- a/log/rotation/file_test.go +++ b/log/rotation/file_test.go @@ -2,7 +2,6 @@ package rotation import ( "bytes" - "io/ioutil" "os" "testing" ) @@ -220,7 +219,7 @@ func TestAppend(t *testing.T) { defer os.Remove("x") b0 := []byte("abc\n") b1 := []byte("def\n") - err := ioutil.WriteFile("x", b0, 0666) + err := os.WriteFile("x", b0, 0666) if err != nil { t.Fatal(err) } diff --git a/protocol/bc/bc.pb.go b/protocol/bc/bc.pb.go index ef7262d..0e42785 100644 --- a/protocol/bc/bc.pb.go +++ b/protocol/bc/bc.pb.go @@ -5,9 +5,11 @@ Package bc is a generated protocol buffer package. It is generated from these files: + bc.proto It has these top-level messages: + Hash Predicate DataItem diff --git a/protocol/bc/bctest/tx.go b/protocol/bc/bctest/tx.go index 8d8c91b..9e1b393 100644 --- a/protocol/bc/bctest/tx.go +++ b/protocol/bc/bctest/tx.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/testutil" ) // EmptyTx produces a minimal valid transaction from "nonce" and diff --git a/protocol/bc/block.go b/protocol/bc/block.go index 3667a2c..3ebd4aa 100644 --- a/protocol/bc/block.go +++ b/protocol/bc/block.go @@ -7,8 +7,8 @@ import ( "github.com/golang/protobuf/proto" "golang.org/x/sync/errgroup" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" ) // UnsignedBlock describes a block with its transactions but no signatures diff --git a/protocol/bc/block_test.go b/protocol/bc/block_test.go index 7e96cc8..0f1a809 100644 --- a/protocol/bc/block_test.go +++ b/protocol/bc/block_test.go @@ -6,11 +6,11 @@ import ( "strings" "testing" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/protocol/txvm/txvmtest" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm/txvmtest" + "github.com/bobg/txvm/testutil" ) var testBlockBytes = mustDecodeHex( diff --git a/protocol/bc/blockheader.go b/protocol/bc/blockheader.go index 3396620..05deeec 100644 --- a/protocol/bc/blockheader.go +++ b/protocol/bc/blockheader.go @@ -5,8 +5,8 @@ import ( "github.com/golang/protobuf/proto" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" ) // Hash computes the unique Chain protocol hash of the BlockHeader. diff --git a/protocol/bc/blockheader_test.go b/protocol/bc/blockheader_test.go index d096ff5..e35f5b3 100644 --- a/protocol/bc/blockheader_test.go +++ b/protocol/bc/blockheader_test.go @@ -4,7 +4,7 @@ import ( "bytes" "testing" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/testutil" ) var filledBlock = &BlockHeader{ diff --git a/protocol/bc/hash.go b/protocol/bc/hash.go index afd8fe8..164736f 100644 --- a/protocol/bc/hash.go +++ b/protocol/bc/hash.go @@ -9,7 +9,7 @@ import ( "fmt" "io" - "github.com/chain/txvm/crypto/sha3" + "github.com/bobg/txvm/crypto/sha3" ) // EmptyStringHash is the hash of the empty string. diff --git a/protocol/bc/merkle.go b/protocol/bc/merkle.go index f2cf2f3..472e03a 100644 --- a/protocol/bc/merkle.go +++ b/protocol/bc/merkle.go @@ -3,7 +3,7 @@ package bc import ( "bytes" - "github.com/chain/txvm/protocol/merkle" + "github.com/bobg/txvm/protocol/merkle" ) // TxMerkleRoot creates a merkle tree from a slice of Transactions and diff --git a/protocol/bc/tx.go b/protocol/bc/tx.go index 9714ca3..3782b44 100644 --- a/protocol/bc/tx.go +++ b/protocol/bc/tx.go @@ -4,9 +4,9 @@ import ( "bytes" "io" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/op" ) // Tx contains the input to an instance of the txvm virtual machine, diff --git a/protocol/bc/tx_test.go b/protocol/bc/tx_test.go index 8ec270c..886e871 100644 --- a/protocol/bc/tx_test.go +++ b/protocol/bc/tx_test.go @@ -8,11 +8,11 @@ import ( "github.com/davecgh/go-spew/spew" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmtest" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmtest" + "github.com/bobg/txvm/testutil" ) var zeroes32 [32]byte diff --git a/protocol/block.go b/protocol/block.go index bce237b..32a60b5 100644 --- a/protocol/block.go +++ b/protocol/block.go @@ -6,12 +6,12 @@ import ( "sync/atomic" "time" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/log" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/patricia" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/log" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/patricia" + "github.com/bobg/txvm/protocol/state" ) var ( diff --git a/protocol/block_test.go b/protocol/block_test.go index a268b37..2a840e6 100644 --- a/protocol/block_test.go +++ b/protocol/block_test.go @@ -11,12 +11,12 @@ import ( "github.com/davecgh/go-spew/spew" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/bc/bctest" - "github.com/chain/txvm/protocol/patricia" - "github.com/chain/txvm/protocol/prottest/memstore" - "github.com/chain/txvm/protocol/state" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/bc/bctest" + "github.com/bobg/txvm/protocol/patricia" + "github.com/bobg/txvm/protocol/prottest/memstore" + "github.com/bobg/txvm/protocol/state" + "github.com/bobg/txvm/testutil" ) func TestGetBlock(t *testing.T) { diff --git a/protocol/builder.go b/protocol/builder.go index b64bc92..b168d19 100644 --- a/protocol/builder.go +++ b/protocol/builder.go @@ -4,11 +4,11 @@ import ( "fmt" "time" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/merkle" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/merkle" + "github.com/bobg/txvm/protocol/state" ) // Some defaults. diff --git a/protocol/merkle/merkle.go b/protocol/merkle/merkle.go index a66fde8..b25d902 100644 --- a/protocol/merkle/merkle.go +++ b/protocol/merkle/merkle.go @@ -5,8 +5,8 @@ import ( "errors" "math" - "github.com/chain/txvm/crypto/sha3" - "github.com/chain/txvm/crypto/sha3pool" + "github.com/bobg/txvm/crypto/sha3" + "github.com/bobg/txvm/crypto/sha3pool" ) var ( diff --git a/protocol/patricia/patricia.go b/protocol/patricia/patricia.go index 1aa4808..3e6aa8b 100644 --- a/protocol/patricia/patricia.go +++ b/protocol/patricia/patricia.go @@ -23,8 +23,8 @@ import ( "bytes" "io" - "github.com/chain/txvm/crypto/sha3pool" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/crypto/sha3pool" + "github.com/bobg/txvm/errors" ) var ( diff --git a/protocol/patricia/patricia_test.go b/protocol/patricia/patricia_test.go index 39f59fa..9f0522b 100644 --- a/protocol/patricia/patricia_test.go +++ b/protocol/patricia/patricia_test.go @@ -11,8 +11,8 @@ import ( "testing" "testing/quick" - "github.com/chain/txvm/crypto/sha3" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/sha3" + "github.com/bobg/txvm/testutil" ) func BenchmarkSingleInsert(b *testing.B) { diff --git a/protocol/protocol.go b/protocol/protocol.go index 063eb99..c0a9101 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -8,7 +8,7 @@ blockchain state. Here are a few examples of typical full node types. -Generator +# Generator A generator has two basic jobs: collecting transactions from other nodes and putting them into blocks. @@ -17,12 +17,12 @@ To add a new block to the blockchain, call GenerateBlock, sign the block (possibly collecting signatures from other parties), and call CommitAppliedBlock. -Signer +# Signer A signer validates blocks generated by the Generator and signs at most one block at each height. -Participant +# Participant A participant node in a network may select outputs for spending and compose transactions. @@ -36,7 +36,7 @@ transaction has been either confirmed or rejected. Note that transactions may be malleable if there's no commitment to TXSIGHASH. -New block sequence +# New block sequence Every new block must be validated against the existing blockchain state. New blocks are validated by calling @@ -59,7 +59,7 @@ A new block goes through the sequence: - Other cored processes are notified of the new block through Store.FinalizeHeight. -Committing a block +# Committing a block As a consumer of the package, there are two ways to commit a new block: CommitBlock and CommitAppliedBlock. @@ -81,10 +81,10 @@ import ( "context" "sync" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/log" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/log" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/state" ) const defaultBlocksPerSnapshot = uint64(100) diff --git a/protocol/protocol_test.go b/protocol/protocol_test.go index dcad3e4..c20b366 100644 --- a/protocol/protocol_test.go +++ b/protocol/protocol_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/prottest/memstore" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/prottest/memstore" ) func TestNewChainHeight(t *testing.T) { diff --git a/protocol/prottest/block.go b/protocol/prottest/block.go index ae3e302..34b7ec3 100644 --- a/protocol/prottest/block.go +++ b/protocol/prottest/block.go @@ -6,12 +6,12 @@ import ( "testing" "time" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/prottest/memstore" - "github.com/chain/txvm/protocol/state" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/prottest/memstore" + "github.com/bobg/txvm/protocol/state" + "github.com/bobg/txvm/testutil" ) var ( diff --git a/protocol/prottest/memstore/memstore.go b/protocol/prottest/memstore/memstore.go index 8d31628..01420b7 100644 --- a/protocol/prottest/memstore/memstore.go +++ b/protocol/prottest/memstore/memstore.go @@ -9,8 +9,8 @@ import ( "fmt" "sync" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/state" ) // MemStore satisfies the Store interface. diff --git a/protocol/recover.go b/protocol/recover.go index cd4eeed..80bfcf8 100644 --- a/protocol/recover.go +++ b/protocol/recover.go @@ -5,9 +5,9 @@ import ( "fmt" "sync/atomic" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/state" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/state" ) // Recover performs crash recovery, restoring the blockchain diff --git a/protocol/recover_test.go b/protocol/recover_test.go index 0f7f991..3b0c15b 100644 --- a/protocol/recover_test.go +++ b/protocol/recover_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/prottest/memstore" - "github.com/chain/txvm/protocol/state" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/prottest/memstore" + "github.com/bobg/txvm/protocol/state" + "github.com/bobg/txvm/testutil" ) func TestRecoverSnapshotNoAdditionalBlocks(t *testing.T) { diff --git a/protocol/state/rawsnapshot.pb.go b/protocol/state/rawsnapshot.pb.go index 1dbed55..55ea13e 100644 --- a/protocol/state/rawsnapshot.pb.go +++ b/protocol/state/rawsnapshot.pb.go @@ -5,9 +5,11 @@ Package state is a generated protocol buffer package. It is generated from these files: + rawsnapshot.proto It has these top-level messages: + RawSnapshot */ package state @@ -15,7 +17,7 @@ package state import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" -import bc "github.com/chain/txvm/protocol/bc" +import bc "github.com/bobg/txvm/protocol/bc" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal diff --git a/protocol/state/serialize.go b/protocol/state/serialize.go index ce234a8..4ede237 100644 --- a/protocol/state/serialize.go +++ b/protocol/state/serialize.go @@ -3,8 +3,8 @@ package state import ( "github.com/golang/protobuf/proto" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/patricia" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/patricia" ) func (s *Snapshot) FromBytes(b []byte) error { diff --git a/protocol/state/snapshot.go b/protocol/state/snapshot.go index 7e2049d..003abcd 100644 --- a/protocol/state/snapshot.go +++ b/protocol/state/snapshot.go @@ -8,9 +8,9 @@ import ( "encoding/binary" "fmt" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/patricia" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/patricia" ) // Snapshot contains a blockchain's state. @@ -148,7 +148,7 @@ func (s *Snapshot) ApplyTx(p *bc.CommitmentsTx) error { for _, n := range p.Tx.Nonces { // Add new nonces. They must not conflict with nonces already // present. - nc, _ := p.NonceCommitments[n.ID] + nc := p.NonceCommitments[n.ID] if nonceTree.Contains(nc) { return errors.Wrapf(ErrConflictingNonce, "nonce %x", n.ID.Bytes()) } diff --git a/protocol/state/snapshot_test.go b/protocol/state/snapshot_test.go index dbbf362..7c6d580 100644 --- a/protocol/state/snapshot_test.go +++ b/protocol/state/snapshot_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" ) func empty(t *testing.T) *Snapshot { diff --git a/protocol/tx_test.go b/protocol/tx_test.go index 7ce3e1c..5cd4b37 100644 --- a/protocol/tx_test.go +++ b/protocol/tx_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/chain/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/bc" ) func TestBadMaxNonceWindow(t *testing.T) { diff --git a/protocol/txbuilder/standard/checksig.go b/protocol/txbuilder/standard/checksig.go index 7ae34b1..82066e3 100644 --- a/protocol/txbuilder/standard/checksig.go +++ b/protocol/txbuilder/standard/checksig.go @@ -1,8 +1,10 @@ package standard // multisigProgCheckSrc expects: -// argument stack: [... s1 s2 ... s_n prog] -// contract stack: [... quorum {p1, p2, ..., p_n} anchor] +// +// argument stack: [... s1 s2 ... s_n prog] +// contract stack: [... quorum {p1, p2, ..., p_n} anchor] +// // It checks that each `s_i` is a valid signature of // the program string `prog`||`anchor` for a public key `p_i`. // There must be exactly `quorum` such valid signatures; diff --git a/protocol/txbuilder/standard/input.go b/protocol/txbuilder/standard/input.go index 64177f4..40b9047 100644 --- a/protocol/txbuilder/standard/input.go +++ b/protocol/txbuilder/standard/input.go @@ -3,17 +3,19 @@ package standard import ( "fmt" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmutil" ) // payToMultisigProgUnlock expects: -// argument stack: [... spendrefdata] -// contract stack: [... quorum {p1,...,p_n} value] +// +// argument stack: [... spendrefdata] +// contract stack: [... quorum {p1,...,p_n} value] +// // It unlocks `value` (placing it on the arg stack) and defers a MultisigProgCheck. const payToMultisigProgUnlockSrcFmt = ` # Contract stack Argument stack Log diff --git a/protocol/txbuilder/standard/issue.go b/protocol/txbuilder/standard/issue.go index 861aa97..6e6b0a3 100644 --- a/protocol/txbuilder/standard/issue.go +++ b/protocol/txbuilder/standard/issue.go @@ -3,11 +3,11 @@ package standard import ( "fmt" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmutil" ) // a versioned asset contract map diff --git a/protocol/txbuilder/standard/output.go b/protocol/txbuilder/standard/output.go index 2dabaf3..48a596b 100644 --- a/protocol/txbuilder/standard/output.go +++ b/protocol/txbuilder/standard/output.go @@ -3,12 +3,14 @@ package standard import ( "fmt" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" ) // payToMultisigProg1 expects: -// argument stack: [... refdata value {p1,...,p_n} quorum] +// +// argument stack: [... refdata value {p1,...,p_n} quorum] +// // It moves them onto the contract stack and then `output`s a contract // that runs a PayToMultisigProgUnlock when next called. const payToMultisigProgSrcFmt1 = ` @@ -36,7 +38,9 @@ var ( ) // payToMultisigProg2 expects: -// argument stack: [... refdata tags value {p1,...,p_n} quorum] +// +// argument stack: [... refdata tags value {p1,...,p_n} quorum] +// // It moves them onto the contract stack and then `output`s a contract // that runs a PayToMultisigProgUnlock when next called. const payToMultisigProgSrcFmt2 = ` diff --git a/protocol/txbuilder/standard/retire.go b/protocol/txbuilder/standard/retire.go index db030d4..7e8e39b 100644 --- a/protocol/txbuilder/standard/retire.go +++ b/protocol/txbuilder/standard/retire.go @@ -1,8 +1,8 @@ package standard import ( - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" ) // expects [... refdata value] on the arg stack diff --git a/protocol/txbuilder/standard/standard.go b/protocol/txbuilder/standard/standard.go index 19be72c..b0922af 100644 --- a/protocol/txbuilder/standard/standard.go +++ b/protocol/txbuilder/standard/standard.go @@ -3,8 +3,8 @@ package standard import ( - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmutil" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmutil" ) // VerifyTxID returns a program that verifies the txid matches the diff --git a/protocol/txbuilder/standard/standard_test.go b/protocol/txbuilder/standard/standard_test.go index b78afdb..0d7d3ac 100644 --- a/protocol/txbuilder/standard/standard_test.go +++ b/protocol/txbuilder/standard/standard_test.go @@ -5,10 +5,10 @@ import ( "encoding/hex" "testing" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txvm/txvmutil" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txvm/txvmutil" + "github.com/bobg/txvm/testutil" ) // TestSeeds ensures we don't change our standard contracts without diff --git a/protocol/txbuilder/template.go b/protocol/txbuilder/template.go index d370c0d..d9949b7 100644 --- a/protocol/txbuilder/template.go +++ b/protocol/txbuilder/template.go @@ -7,15 +7,15 @@ import ( "sort" "time" - "github.com/chain/txvm/crypto/ed25519" - i10rjson "github.com/chain/txvm/encoding/json" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txbuilder/standard" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmutil" + "github.com/bobg/txvm/crypto/ed25519" + i10rjson "github.com/bobg/txvm/encoding/json" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txbuilder/standard" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmutil" ) const latestOutputVersion = 2 diff --git a/protocol/txbuilder/txbuilder_test.go b/protocol/txbuilder/txbuilder_test.go index 271c96d..309e476 100644 --- a/protocol/txbuilder/txbuilder_test.go +++ b/protocol/txbuilder/txbuilder_test.go @@ -7,14 +7,14 @@ import ( "testing" "time" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/crypto/sha3pool" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txbuilder/standard" - "github.com/chain/txvm/protocol/txbuilder/txresult" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/crypto/sha3pool" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txbuilder/standard" + "github.com/bobg/txvm/protocol/txbuilder/txresult" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/testutil" ) // duplicated from core/key/store.go. diff --git a/protocol/txbuilder/txresult/result.go b/protocol/txbuilder/txresult/result.go index 2a0b23c..cca6837 100644 --- a/protocol/txbuilder/txresult/result.go +++ b/protocol/txbuilder/txresult/result.go @@ -4,10 +4,10 @@ import ( "bytes" "sync" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txbuilder/standard" - "github.com/chain/txvm/protocol/txvm" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txbuilder/standard" + "github.com/bobg/txvm/protocol/txvm" ) // Result is a container for information that can be parsed from the diff --git a/protocol/txbuilder/txresult/txresult_test.go b/protocol/txbuilder/txresult/txresult_test.go index bc0aebb..bdc8c9f 100644 --- a/protocol/txbuilder/txresult/txresult_test.go +++ b/protocol/txbuilder/txresult/txresult_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/crypto/sha3pool" - "github.com/chain/txvm/protocol/bc" - "github.com/chain/txvm/protocol/txbuilder" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/crypto/sha3pool" + "github.com/bobg/txvm/protocol/bc" + "github.com/bobg/txvm/protocol/txbuilder" + "github.com/bobg/txvm/testutil" ) // duplicated from core/key/store.go. @@ -33,6 +33,9 @@ func TestResult(t *testing.T) { derived := testutil.TestXPrv.Derive(path) return derived.Sign(data), nil }) + if err != nil { + t.Fatal(err) + } tx, err := tpl.Tx() if err != nil { t.Fatal(err) diff --git a/protocol/txvm/asm/asm.go b/protocol/txvm/asm/asm.go index cfc8815..c394500 100644 --- a/protocol/txvm/asm/asm.go +++ b/protocol/txvm/asm/asm.go @@ -9,9 +9,9 @@ import ( "strconv" "strings" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/op" ) type jump struct { diff --git a/protocol/txvm/asm/asm_test.go b/protocol/txvm/asm/asm_test.go index d9d74e2..b52a387 100644 --- a/protocol/txvm/asm/asm_test.go +++ b/protocol/txvm/asm/asm_test.go @@ -2,10 +2,10 @@ package asm import ( "bytes" - "io/ioutil" + "os" "testing" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/op" ) func TestAssembler(t *testing.T) { @@ -71,7 +71,7 @@ func TestAssembler(t *testing.T) { func BenchmarkAssemble(b *testing.B) { b.StopTimer() - prog, err := ioutil.ReadFile("exampletx.asm") + prog, err := os.ReadFile("exampletx.asm") if err != nil { b.Fatal(err) } diff --git a/protocol/txvm/asm/doc.go b/protocol/txvm/asm/doc.go index 6a0a423..5172c43 100644 --- a/protocol/txvm/asm/doc.go +++ b/protocol/txvm/asm/doc.go @@ -1,16 +1,15 @@ /* - Package asm provides an assembler and disassembler for txvm bytecode. In the txvm assembly language implemented by this package, each opcode in the txvm instruction set is represented by its all-lowercase name (e.g. "swap" and "add"). Literals are represented as follows: - - integers: 123, -72 - - hex strings: x'ec7a' or x"ec7a" - - readable strings: 'foo' or "foo" (with \ escaping) - - program strings: [...assembly code...] - - tuples: {'V', 20, x'ec7a220e...', x'b773ae91...'} + - integers: 123, -72 + - hex strings: x'ec7a' or x"ec7a" + - readable strings: 'foo' or "foo" (with \ escaping) + - program strings: [...assembly code...] + - tuples: {'V', 20, x'ec7a220e...', x'b773ae91...'} An identifier preceded with $ is a symbolic jump target. A conditional jump to target $foo can be written as jumpif:$foo. An unconditional @@ -19,16 +18,15 @@ jump to target $foo can be written as jump:$foo. The assembler also supports a handful of built-in convenience macros that expand to longer sequences of instructions: - - bool: not not (convert any data value to a 0 or 1) - - swap: 1 roll (swap top two items on the stack) - - sub: neg add (subtract integers) - - splitzero: 0 split - - le: gt not (less than or equal) - - ge: swap le (greater than or equal) - - lt: swap gt (less than) + - bool: not not (convert any data value to a 0 or 1) + - swap: 1 roll (swap top two items on the stack) + - sub: neg add (subtract integers) + - splitzero: 0 split + - le: gt not (less than or equal) + - ge: swap le (greater than or equal) + - lt: swap gt (less than) Whitespace between tokens in assembler input is insignificant. Comments are introduced by # and continue to the end of line. - */ package asm diff --git a/protocol/txvm/asm/runlimit_test.go b/protocol/txvm/asm/runlimit_test.go index 080d42c..b9a40f9 100644 --- a/protocol/txvm/asm/runlimit_test.go +++ b/protocol/txvm/asm/runlimit_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/chain/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm" ) func TestRunlimits(t *testing.T) { diff --git a/protocol/txvm/asm/scanner.go b/protocol/txvm/asm/scanner.go index c6e2155..4f63ddd 100644 --- a/protocol/txvm/asm/scanner.go +++ b/protocol/txvm/asm/scanner.go @@ -5,7 +5,7 @@ import ( "unicode" "unicode/utf8" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) type scanner struct { @@ -48,7 +48,6 @@ const ( // next reads the next Unicode char into s.ch. // s.ch < 0 means end-of-file. -// func (s *scanner) next() { if s.rdOffset < len(s.srcstr) { s.offset = s.rdOffset diff --git a/protocol/txvm/bitwise.go b/protocol/txvm/bitwise.go index 081aa60..fcca1f8 100644 --- a/protocol/txvm/bitwise.go +++ b/protocol/txvm/bitwise.go @@ -1,8 +1,8 @@ package txvm import ( - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/op" ) // ErrBitLen is returned when a binary bitwise op is called diff --git a/protocol/txvm/complex_ops_test.go b/protocol/txvm/complex_ops_test.go index 3888c1b..48d552c 100644 --- a/protocol/txvm/complex_ops_test.go +++ b/protocol/txvm/complex_ops_test.go @@ -4,8 +4,8 @@ import ( "math" "testing" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/op" ) func TestComplexOpcodes(t *testing.T) { diff --git a/protocol/txvm/contract.go b/protocol/txvm/contract.go index f455dbf..5249e05 100644 --- a/protocol/txvm/contract.go +++ b/protocol/txvm/contract.go @@ -3,7 +3,7 @@ package txvm import ( "fmt" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) var ( diff --git a/protocol/txvm/control.go b/protocol/txvm/control.go index fe45f56..b077bb3 100644 --- a/protocol/txvm/control.go +++ b/protocol/txvm/control.go @@ -1,8 +1,8 @@ package txvm import ( - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" ) var ( diff --git a/protocol/txvm/crypto.go b/protocol/txvm/crypto.go index 12fec74..1bde4d5 100644 --- a/protocol/txvm/crypto.go +++ b/protocol/txvm/crypto.go @@ -3,9 +3,9 @@ package txvm import ( "crypto/sha256" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/crypto/sha3" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/crypto/sha3" + "github.com/bobg/txvm/errors" ) var ( diff --git a/protocol/txvm/data.go b/protocol/txvm/data.go index afdcf54..7b4cd5b 100644 --- a/protocol/txvm/data.go +++ b/protocol/txvm/data.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "fmt" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) // ErrInt is returned when int is called on a byte string diff --git a/protocol/txvm/doc.go b/protocol/txvm/doc.go index 0712f02..f60536c 100644 --- a/protocol/txvm/doc.go +++ b/protocol/txvm/doc.go @@ -1,5 +1,4 @@ /* - Package txvm implements Chain Protocol transactions. A transaction is a program (as a bytecode string) that is executed by @@ -22,15 +21,15 @@ via the input instruction. During execution, value-manipulating structures are produced as side-effects: - - Issuances: new units of a caller-defined asset type are created. - - Outputs: units of an asset are "locked" by specifying the - conditions needed to unlock and spend them. An output is simply a - contract that has suspended itself with the output instruction and - that contains some value on its stack. - - Inputs: previously locked value is unlocked by satisfying an - output's conditions. - - Retirements: units of an asset type are permanently removed from - circulation. + - Issuances: new units of a caller-defined asset type are created. + - Outputs: units of an asset are "locked" by specifying the + conditions needed to unlock and spend them. An output is simply a + contract that has suspended itself with the output instruction and + that contains some value on its stack. + - Inputs: previously locked value is unlocked by satisfying an + output's conditions. + - Retirements: units of an asset type are permanently removed from + circulation. Significant events during processing, including the creation of the above-named structures, cause relevant entries to accumulate in the @@ -38,6 +37,5 @@ virtual machine's "transaction log." The log may be inspected to discover the transaction's effects (especially to find the IDs of inputs and outputs for removing from the utxo set and adding to it, respectively). The log is hashed to get the overall transaction ID. - */ package txvm diff --git a/protocol/txvm/entries.go b/protocol/txvm/entries.go index 854eafe..981167e 100644 --- a/protocol/txvm/entries.go +++ b/protocol/txvm/entries.go @@ -3,7 +3,7 @@ package txvm import ( "fmt" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) // Type codes for inspected entries and for log items. diff --git a/protocol/txvm/error.go b/protocol/txvm/error.go index 1ef934f..6b56b5c 100644 --- a/protocol/txvm/error.go +++ b/protocol/txvm/error.go @@ -3,7 +3,7 @@ package txvm import ( "fmt" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) type vmError error diff --git a/protocol/txvm/examples/convertible.md b/protocol/txvm/examples/convertible.md index 35a1f7d..7e960f1 100644 --- a/protocol/txvm/examples/convertible.md +++ b/protocol/txvm/examples/convertible.md @@ -69,7 +69,7 @@ in which some amount of the partner asset is destroyed while dictating how many We’ll treat the case of normal issuance as solved. You can see how Chain does issuance in -[the standard asset-issuance contract](https://github.com/chain/txvm/blob/main/protocol/txbuilder/standard/issue.go) +[the standard asset-issuance contract](https://github.com/bobg/txvm/blob/main/protocol/txbuilder/standard/issue.go) in the chain/txvm GitHub repo. For conversion, @@ -134,7 +134,7 @@ and the tuple full of pubkeys on the argument stack. in addition to the pre-tag tuple.) The specification for how an asset ID is computed can be found -[here](https://github.com/chain/txvm/blob/main/specifications/txvm.md#asset-id). +[here](https://github.com/bobg/txvm/blob/main/specifications/txvm.md#asset-id). ``` contract stack arg stack @@ -209,7 +209,7 @@ Here’s where we would insert the standard asset-issuance contract (which, again, can be found -[here](https://github.com/chain/txvm/blob/main/specifications/txvm.md#asset-id)). +[here](https://github.com/bobg/txvm/blob/main/specifications/txvm.md#asset-id)). It needs to be followed by: ``` diff --git a/protocol/txvm/gen.go b/protocol/txvm/gen.go index 2d7141f..28707e3 100644 --- a/protocol/txvm/gen.go +++ b/protocol/txvm/gen.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore // This runs at "go generate" time, producing opgen.go from op/op.go. @@ -19,7 +20,7 @@ func main() { out, err := os.Create(opgenName) must(err) fmt.Fprint(out, "// Auto-generated from op/op.go by gen.go\n\npackage txvm\n\n") - fmt.Fprintln(out, `import "github.com/chain/txvm/protocol/txvm/op"`) + fmt.Fprintln(out, `import "github.com/bobg/txvm/protocol/txvm/op"`) fmt.Fprint(out, "var opFuncs [256]func(*VM)\n\n") diff --git a/protocol/txvm/introspection_test.go b/protocol/txvm/introspection_test.go index 9d1630b..ad6dc00 100644 --- a/protocol/txvm/introspection_test.go +++ b/protocol/txvm/introspection_test.go @@ -3,8 +3,8 @@ package txvm import ( "testing" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/testutil" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/testutil" ) func TestIntrospection(t *testing.T) { diff --git a/protocol/txvm/item.go b/protocol/txvm/item.go index 9b9ff8e..2333ee4 100644 --- a/protocol/txvm/item.go +++ b/protocol/txvm/item.go @@ -6,8 +6,8 @@ import ( "fmt" "strings" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/op" ) // Item is an interface for all txvm stack items. diff --git a/protocol/txvm/log.go b/protocol/txvm/log.go index d96fa2e..f8efc72 100644 --- a/protocol/txvm/log.go +++ b/protocol/txvm/log.go @@ -1,6 +1,6 @@ package txvm -import "github.com/chain/txvm/errors" +import "github.com/bobg/txvm/errors" // ErrFinalized is returned when an op that logs an item // is called after finalize has been called. diff --git a/protocol/txvm/math.go b/protocol/txvm/math.go index cf78309..27f61d9 100644 --- a/protocol/txvm/math.go +++ b/protocol/txvm/math.go @@ -1,9 +1,9 @@ package txvm import ( - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" + "github.com/bobg/txvm/protocol/txvm/op" ) func opAdd(vm *VM) { diff --git a/protocol/txvm/op/gen.go b/protocol/txvm/op/gen.go index 0439309..d245e0e 100644 --- a/protocol/txvm/op/gen.go +++ b/protocol/txvm/op/gen.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore // This runs at "go generate" time, producing opgen.go from op.go. diff --git a/protocol/txvm/opgen.go b/protocol/txvm/opgen.go index 0a4bfc4..40e873c 100644 --- a/protocol/txvm/opgen.go +++ b/protocol/txvm/opgen.go @@ -2,7 +2,7 @@ package txvm -import "github.com/chain/txvm/protocol/txvm/op" +import "github.com/bobg/txvm/protocol/txvm/op" var opFuncs [256]func(*VM) diff --git a/protocol/txvm/option.go b/protocol/txvm/option.go index b23cb60..ea50afc 100644 --- a/protocol/txvm/option.go +++ b/protocol/txvm/option.go @@ -5,7 +5,7 @@ import ( "fmt" "io" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/op" ) // Option is the type of a function that can be passed as an option to diff --git a/protocol/txvm/simple_ops_test.go b/protocol/txvm/simple_ops_test.go index fc9e0c8..ea1bbcf 100644 --- a/protocol/txvm/simple_ops_test.go +++ b/protocol/txvm/simple_ops_test.go @@ -6,8 +6,8 @@ import ( "math" "testing" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm/op" ) func TestSimpleOpcodes(t *testing.T) { diff --git a/protocol/txvm/stack.go b/protocol/txvm/stack.go index 883d01b..0a8cdee 100644 --- a/protocol/txvm/stack.go +++ b/protocol/txvm/stack.go @@ -1,7 +1,7 @@ package txvm import ( - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) type stack []Item diff --git a/protocol/txvm/strings.go b/protocol/txvm/strings.go index a60fb9c..3a32c65 100644 --- a/protocol/txvm/strings.go +++ b/protocol/txvm/strings.go @@ -1,6 +1,6 @@ package txvm -import "github.com/chain/txvm/errors" +import "github.com/bobg/txvm/errors" // ErrSliceRange is returned when slice is called with // a range that is invalid. diff --git a/protocol/txvm/tx.go b/protocol/txvm/tx.go index 6a68f3b..af57f02 100644 --- a/protocol/txvm/tx.go +++ b/protocol/txvm/tx.go @@ -1,8 +1,8 @@ package txvm import ( - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/merkle" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/merkle" ) // ErrUnfinalized is returned when txid is called before finalize. diff --git a/protocol/txvm/txvmtest/txvmtest.go b/protocol/txvm/txvmtest/txvmtest.go index 0149803..2ae1d3c 100644 --- a/protocol/txvm/txvmtest/txvmtest.go +++ b/protocol/txvm/txvmtest/txvmtest.go @@ -4,9 +4,9 @@ import ( "encoding/hex" "fmt" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" ) // sample transactions diff --git a/protocol/txvm/txvmutil/builder.go b/protocol/txvm/txvmutil/builder.go index 2010641..1ded7a0 100644 --- a/protocol/txvm/txvmutil/builder.go +++ b/protocol/txvm/txvmutil/builder.go @@ -10,7 +10,7 @@ import ( "fmt" "math" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/op" ) // Builder helps programmatically build txvm programs. diff --git a/protocol/txvm/txvmutil/builder_test.go b/protocol/txvm/txvmutil/builder_test.go index 3c767ff..b8a4eef 100644 --- a/protocol/txvm/txvmutil/builder_test.go +++ b/protocol/txvm/txvmutil/builder_test.go @@ -4,8 +4,8 @@ import ( "bytes" "testing" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/op" ) func newBuilder() *Builder { diff --git a/protocol/txvm/values.go b/protocol/txvm/values.go index ee219fb..28856bc 100644 --- a/protocol/txvm/values.go +++ b/protocol/txvm/values.go @@ -4,8 +4,8 @@ import ( "bytes" "fmt" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" ) var ( diff --git a/protocol/txvm/vm.go b/protocol/txvm/vm.go index c5f1f10..d9c1e39 100644 --- a/protocol/txvm/vm.go +++ b/protocol/txvm/vm.go @@ -1,9 +1,9 @@ package txvm import ( - "github.com/chain/txvm/errors" - "github.com/chain/txvm/math/checked" - "github.com/chain/txvm/protocol/txvm/op" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/math/checked" + "github.com/bobg/txvm/protocol/txvm/op" ) //go:generate go run gen.go diff --git a/protocol/txvm/vm_test.go b/protocol/txvm/vm_test.go index 818a80c..8c8504b 100644 --- a/protocol/txvm/vm_test.go +++ b/protocol/txvm/vm_test.go @@ -5,11 +5,11 @@ import ( "testing" "testing/quick" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/txvm" - "github.com/chain/txvm/protocol/txvm/asm" - "github.com/chain/txvm/protocol/txvm/op" - "github.com/chain/txvm/protocol/txvm/txvmtest" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/txvm" + "github.com/bobg/txvm/protocol/txvm/asm" + "github.com/bobg/txvm/protocol/txvm/op" + "github.com/bobg/txvm/protocol/txvm/txvmtest" ) func TestVMFuzz(t *testing.T) { diff --git a/protocol/validation/validation.go b/protocol/validation/validation.go index 01fe429..be5a8bb 100644 --- a/protocol/validation/validation.go +++ b/protocol/validation/validation.go @@ -5,9 +5,9 @@ Chain Protocol spec. package validation import ( - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" ) var ( diff --git a/protocol/validation/validation_test.go b/protocol/validation/validation_test.go index 9b5bafc..64899b1 100644 --- a/protocol/validation/validation_test.go +++ b/protocol/validation/validation_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/errors" - "github.com/chain/txvm/protocol/bc" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/errors" + "github.com/bobg/txvm/protocol/bc" ) func TestBlock(t *testing.T) { diff --git a/testutil/expect.go b/testutil/expect.go index 1597b06..24d5f47 100644 --- a/testutil/expect.go +++ b/testutil/expect.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/chain/txvm/errors" + "github.com/bobg/txvm/errors" ) var wd, _ = os.Getwd() diff --git a/testutil/keys.go b/testutil/keys.go index d7d5e49..7d99084 100644 --- a/testutil/keys.go +++ b/testutil/keys.go @@ -3,8 +3,8 @@ package testutil import ( miscreant "github.com/miscreant/miscreant/go" - "github.com/chain/txvm/crypto/ed25519" - "github.com/chain/txvm/crypto/ed25519/chainkd" + "github.com/bobg/txvm/crypto/ed25519" + "github.com/bobg/txvm/crypto/ed25519/chainkd" ) var ( diff --git a/whitepaper/bibliography.bib b/whitepaper/bibliography.bib index ec0f7bf..9738a14 100644 --- a/whitepaper/bibliography.bib +++ b/whitepaper/bibliography.bib @@ -99,7 +99,7 @@ @misc{chainvm @misc{txvm-spec, TITLE = {TxVM specification}, - URL = {https://github.com/chain/txvm/blob/main/specifications/txvm.md}, + URL = {https://github.com/bobg/txvm/blob/main/specifications/txvm.md}, AUTHOR = {Chain}, YEAR = {2018}, MONTH = {3}, diff --git a/whitepaper/whitepaper.tex b/whitepaper/whitepaper.tex index efc125c..35314b9 100644 --- a/whitepaper/whitepaper.tex +++ b/whitepaper/whitepaper.tex @@ -579,7 +579,7 @@ \section{Further reading} We have a full specification and implementation of \txvm{} available as an open-source project on GitHub, at -\href{https://github.com/chain/txvm}{\texttt{github.com/chain/txvm}}. +\href{https://github.com/bobg/txvm}{\texttt{github.com/bobg/txvm}}. One of us (Yun) presented \txvm{} at the Stanford Blockchain Protocol Analysis and Security Engineering (\textsc{bpase}) 2018