Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Convert utility rework. Option to sign transactions added. #1420

Merged
merged 6 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ build-compiler-windows:

release-compiler: ver build-compiler-linux build-compiler-darwin build-compiler-windows

dist-compiler: release-compiler
@mkdir -p build/dist
@cd ./build/; zip -j ./dist/compiler_$(VERSION)_Windows-amd64.zip ./bin/windows-amd64/compiler*
@cd ./build/bin/linux-amd64/; tar pzcvf ../../dist/compiler_$(VERSION)_Linux-amd64.tar.gz ./compiler*
@cd ./build/bin/darwin-amd64/; tar pzcvf ../../dist/compiler_$(VERSION)_macOS-amd64.tar.gz ./compiler*

build-statehash-linux:
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o build/bin/linux-amd64/statehash ./cmd/statehash
build-statehash-darwin:
Expand All @@ -189,11 +195,20 @@ build-statehash-windows:

release-statehash: ver build-statehash-linux build-statehash-darwin build-statehash-windows

dist-compiler: release-compiler
build-convert-linux:
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o build/bin/linux-amd64/convert ./cmd/convert
build-convert-darwin:
@CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o build/bin/darwin-amd64/convert ./cmd/convert
build-convert-windows:
@CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o build/bin/windows-amd64/convert.exe ./cmd/convert

release-convert: ver build-convert-linux build-convert-darwin build-convert-windows

dist-convert: release-convert
@mkdir -p build/dist
@cd ./build/; zip -j ./dist/compiler_$(VERSION)_Windows-amd64.zip ./bin/windows-amd64/compiler*
@cd ./build/bin/linux-amd64/; tar pzcvf ../../dist/compiler_$(VERSION)_Linux-amd64.tar.gz ./compiler*
@cd ./build/bin/darwin-amd64/; tar pzcvf ../../dist/compiler_$(VERSION)_macOS-amd64.tar.gz ./compiler*
@cd ./build/; zip -j ./dist/convert_$(VERSION)_Windows-amd64.zip ./bin/windows-amd64/convert*
@cd ./build/bin/linux-amd64/; tar pzcvf ../../dist/convert_$(VERSION)_Linux-amd64.tar.gz ./convert*
@cd ./build/bin/darwin-amd64/; tar pzcvf ../../dist/convert_$(VERSION)_macOS-amd64.tar.gz ./convert*

dist: clean dist-chaincmp dist-importer dist-node dist-wallet dist-compiler

Expand Down
47 changes: 47 additions & 0 deletions cmd/convert/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Utility `convert`

The `convert` utility is designed for converting Waves transactions between JSON to Binary formats, and vice versa.
It can also be used to sign unsigned transactions while transforming their representation.

## Command line options

```bash
nickeskov marked this conversation as resolved.
Show resolved Hide resolved
-scheme string
Network scheme byte. Defaults to 'W' (MainNet).
-to-json
Convert the transaction to JSON representation. Sign the transaction if a private key is provided.
-to-binary
Convert the transaction to binary representation. Sign the transaction if a private key is provided.
-base64
Use Base64 as the binary transaction encoding.
-private-key string
Private key to sign the transaction. Please provide the key in Base58 string.
-in string
Input file path. Defaults to empty string. If empty, reads from STDIN.
-out string
Output file path. Defaults to empty string. If empty, writes to STDOUT.
```
## Conversion to the same format

By default, `convert` detects the format of input data and attempts to convert the transaction to the opposite format: from binary to JSON or from JSON to binary.
However, using the options `-to-json` and `-to-binary`, it is possible to override this rule and produce the resulting transaction in the same format as the source.
This is useful with the `-sign` option to produce a signed transaction from an unsigned one.

## Piping

The result of a transaction conversion can be piped to other utilities.

For example, the transaction converted from a file can be piped to `curl`.
```bash
./convert -private-key <private key base58> -to-json -in <transaction file> | curl -X POST -H 'accept: application/json' -H 'Content-Type: application/json' --data-binary @- 'https://nodes-testnet.wavesnodes.com/transactions/broadcast'
```

The source transaction for conversion can be read from STDIN.
```bash
./convert -base64 < <Base64 transaction file>
nickeskov marked this conversation as resolved.
Show resolved Hide resolved
```

Or both:
```bash
convert -private-key <private key Base58> -to-json < ~/Temp/convert/transfer-unsigned.json | curl -X POST -H 'accept: application/json' -H 'Content-Type: application/json' --data-binary @- 'https://nodes-testnet.wavesnodes.com/transactions/broadcast'
```
122 changes: 122 additions & 0 deletions cmd/convert/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package main

import (
"flag"
"fmt"
"io"
"log"
"os"
"path"

"github.com/wavesplatform/gowaves/pkg/crypto"
"github.com/wavesplatform/gowaves/pkg/proto"
)

type config struct {
scheme proto.Scheme
sk *crypto.SecretKey
in io.ReadCloser
out io.WriteCloser
toJSON bool
toBinary bool
base64 bool
}

func (c *config) parse() error {
var (
scheme, privateKey, in, out string
)
flag.StringVar(&scheme, "scheme", "W", "Network scheme byte. Defaults to 'W' (MainNet).")
flag.BoolVar(&c.toJSON, "to-json", false,
"Convert the transaction to JSON representation. Sign the transaction if a private key is provided.")
flag.BoolVar(&c.toBinary, "to-binary", false,
"Convert the transaction to binary representation. Sign the transaction if a private key is provided.")
flag.BoolVar(&c.base64, "base64", false, "Use Base64 as the binary transaction encoding.")
flag.StringVar(&privateKey, "private-key", "",
"Private key to sign the transaction. Please provide the key in Base58 string.")
flag.StringVar(&in, "in", "", "Input file path. Defaults to empty string. If empty, reads from STDIN.")
flag.StringVar(&out, "out", "", "Output file path. Defaults to empty string. If empty, writes to STDOUT.")
flag.Parse()

if len(scheme) != 1 {
return fmt.Errorf("invalid network scheme %q", scheme)
}
c.scheme = []byte(scheme)[0]

if len(privateKey) != 0 {
sk, err := crypto.NewSecretKeyFromBase58(privateKey)
if err != nil {
return fmt.Errorf("failed to parse private key: %w", err)
}
c.sk = &sk
}
if inErr := c.setInput(in); inErr != nil {
return inErr
}
if outErr := c.setOutput(out); outErr != nil {
return outErr
}
return nil
}

func (c *config) setInput(str string) error {
if len(str) == 0 {
c.in = os.Stdin
return nil
}
fi, err := os.Stat(str)
if os.IsNotExist(err) {
return fmt.Errorf("file %q does not exist", str)
}
if err != nil {
return fmt.Errorf("invalid file path: %w", err)
}
if fi.IsDir() {
return fmt.Errorf("path %q is not a file", str)
}
c.in, err = os.Open(path.Clean(str))
if err != nil {
return fmt.Errorf("failed to open input file %q: %w", str, err)
}
return nil
}

func (c *config) createOutputFile(fn string) error {
f, err := os.Create(path.Clean(fn))
if err != nil {
return fmt.Errorf("failed to open output file %q: %w", fn, err)
}
c.out = f
return nil
}

func (c *config) setOutput(str string) error {
if len(str) == 0 {
c.out = os.Stdout
return nil
}
fi, err := os.Stat(str)
if os.IsNotExist(err) {
return c.createOutputFile(str)
}
if err != nil {
return fmt.Errorf("invalid file path: %w", err)
}
if fi.IsDir() {
return fmt.Errorf("path %q is not a file", str)
}
return c.createOutputFile(str)
}

func (c *config) close() {
nickeskov marked this conversation as resolved.
Show resolved Hide resolved
if c.in != nil {
if err := c.in.Close(); err != nil {
log.Printf("Failed to close input: %v", err)
}
}
if c.out != nil {
if err := c.out.Close(); err != nil {
log.Printf("Failed to close output: %v", err)
}
}
}
Loading
Loading