Merge pull request #752 from nspcc-dev/fix/fixed8

cli: implement Fixed8Flag
This commit is contained in:
Roman Khimov 2020-03-16 15:11:46 +03:00 committed by GitHub
commit d742733e26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 45 deletions

75
cli/flags/fixed8.go Normal file
View file

@ -0,0 +1,75 @@
package flags
import (
"flag"
"strings"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/urfave/cli"
)
// Fixed8 is a wrapper for Uint160 with flag.Value methods.
type Fixed8 struct {
Value util.Fixed8
}
// Fixed8Flag is a flag with type string.
type Fixed8Flag struct {
Name string
Usage string
Value Fixed8
}
var (
_ flag.Value = (*Fixed8)(nil)
_ cli.Flag = Fixed8Flag{}
)
// String implements fmt.Stringer interface.
func (a Fixed8) String() string {
return a.Value.String()
}
// Set implements flag.Value interface.
func (a *Fixed8) Set(s string) error {
f, err := util.Fixed8FromString(s)
if err != nil {
return cli.NewExitError(err, 1)
}
a.Value = f
return nil
}
// Fixed8 casts address to util.Fixed8.
func (a *Fixed8) Fixed8() util.Fixed8 {
return a.Value
}
// String returns a readable representation of this value
// (for usage defaults).
func (f Fixed8Flag) String() string {
var names []string
eachName(f.Name, func(name string) {
names = append(names, getNameHelp(name))
})
return strings.Join(names, ", ") + "\t" + f.Usage
}
// GetName returns the name of the flag.
func (f Fixed8Flag) GetName() string {
return f.Name
}
// Apply populates the flag given the flag set and environment
// Ignores errors.
func (f Fixed8Flag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Var(&f.Value, name, f.Usage)
})
}
// Fixed8FromContext returns parsed util.Fixed8 value provided flag name.
func Fixed8FromContext(ctx *cli.Context, name string) util.Fixed8 {
return ctx.Generic(name).(*Fixed8Flag).Value.Fixed8()
}

View file

@ -51,7 +51,7 @@ var (
Name: "address, a", Name: "address, a",
Usage: "address to use as transaction signee (and gas source)", Usage: "address to use as transaction signee (and gas source)",
} }
gasFlag = cli.Float64Flag{ gasFlag = flags.Fixed8Flag{
Name: "gas, g", Name: "gas, g",
Usage: "gas to add to the transaction", Usage: "gas to add to the transaction",
} }
@ -411,7 +411,7 @@ func invokeInternal(ctx *cli.Context, withMethod bool, signAndPush bool) error {
} }
if signAndPush { if signAndPush {
gas = util.Fixed8FromFloat(ctx.Float64("gas")) gas = flags.Fixed8FromContext(ctx, "gas")
acc, err = getAccFromContext(ctx) acc, err = getAccFromContext(ctx)
if err != nil { if err != nil {
return err return err
@ -593,7 +593,7 @@ func contractDeploy(ctx *cli.Context) error {
if len(endpoint) == 0 { if len(endpoint) == 0 {
return cli.NewExitError(errNoEndpoint, 1) return cli.NewExitError(errNoEndpoint, 1)
} }
gas := util.Fixed8FromFloat(ctx.Float64("gas")) gas := flags.Fixed8FromContext(ctx, "gas")
acc, err := getAccFromContext(ctx) acc, err := getAccFromContext(ctx)
if err != nil { if err != nil {

View file

@ -85,7 +85,7 @@ func newNEP5Commands() []cli.Command {
Name: "amount", Name: "amount",
Usage: "Amount of asset to send", Usage: "Amount of asset to send",
}, },
cli.StringFlag{ flags.Fixed8Flag{
Name: "gas", Name: "gas",
Usage: "Amount of GAS to attach to a tx", Usage: "Amount of GAS to attach to a tx",
}, },
@ -309,19 +309,9 @@ func transferNEP5(ctx *cli.Context) error {
emit.AppCall(w.BinWriter, token.Hash, false) emit.AppCall(w.BinWriter, token.Hash, false)
emit.Opcode(w.BinWriter, opcode.THROWIFNOT) emit.Opcode(w.BinWriter, opcode.THROWIFNOT)
var gas util.Fixed8 gas := flags.Fixed8FromContext(ctx, "gas")
if gasString := ctx.String("gas"); gasString != "" {
gas, err = util.Fixed8FromString(gasString)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid GAS amount: %v", err), 1)
}
}
tx := transaction.NewInvocationTX(w.Bytes(), gas) tx := transaction.NewInvocationTX(w.Bytes(), gas)
tx.Attributes = append(tx.Attributes, transaction.Attribute{ tx.AddVerificationHash(from)
Usage: transaction.Script,
Data: from.BytesBE(),
})
if err := request.AddInputsAndUnspentsToTx(tx, fromFlag.String(), core.UtilityTokenID(), gas, c); err != nil { if err := request.AddInputsAndUnspentsToTx(tx, fromFlag.String(), core.UtilityTokenID(), gas, c); err != nil {
return cli.NewExitError(fmt.Errorf("can't add GAS to a tx: %v", err), 1) return cli.NewExitError(fmt.Errorf("can't add GAS to a tx: %v", err), 1)

View file

@ -559,37 +559,26 @@ func (dao *dao) StoreAsTransaction(tx *transaction.Transaction, index uint32) er
// IsDoubleSpend verifies that the input transactions are not double spent. // IsDoubleSpend verifies that the input transactions are not double spent.
func (dao *dao) IsDoubleSpend(tx *transaction.Transaction) bool { func (dao *dao) IsDoubleSpend(tx *transaction.Transaction) bool {
if len(tx.Inputs) == 0 { return dao.checkUsedInputs(tx.Inputs, state.CoinSpent)
return false
}
for _, inputs := range transaction.GroupInputsByPrevHash(tx.Inputs) {
prevHash := inputs[0].PrevHash
unspent, err := dao.GetUnspentCoinState(prevHash)
if err != nil {
return false
}
for _, input := range inputs {
if int(input.PrevIndex) >= len(unspent.States) || (unspent.States[input.PrevIndex].State&state.CoinSpent) != 0 {
return true
}
}
}
return false
} }
// IsDoubleClaim verifies that given claim inputs are not already claimed by another tx. // IsDoubleClaim verifies that given claim inputs are not already claimed by another tx.
func (dao *dao) IsDoubleClaim(claim *transaction.ClaimTX) bool { func (dao *dao) IsDoubleClaim(claim *transaction.ClaimTX) bool {
if len(claim.Claims) == 0 { return dao.checkUsedInputs(claim.Claims, state.CoinClaimed)
}
func (dao *dao) checkUsedInputs(inputs []transaction.Input, coin state.Coin) bool {
if len(inputs) == 0 {
return false return false
} }
for _, inputs := range transaction.GroupInputsByPrevHash(claim.Claims) { for _, inputs := range transaction.GroupInputsByPrevHash(inputs) {
prevHash := inputs[0].PrevHash prevHash := inputs[0].PrevHash
unspent, err := dao.GetUnspentCoinState(prevHash) unspent, err := dao.GetUnspentCoinState(prevHash)
if err != nil { if err != nil {
return true return true
} }
for _, input := range inputs { for _, input := range inputs {
if int(input.PrevIndex) >= len(unspent.States) || (unspent.States[input.PrevIndex].State&state.CoinClaimed) != 0 { if int(input.PrevIndex) >= len(unspent.States) || (unspent.States[input.PrevIndex].State&coin) != 0 {
return true return true
} }
} }

View file

@ -91,6 +91,14 @@ func (t *Transaction) AddInput(in *Input) {
t.Inputs = append(t.Inputs, *in) t.Inputs = append(t.Inputs, *in)
} }
// AddVerificationHash adds a script attribute for transaction verification.
func (t *Transaction) AddVerificationHash(addr util.Uint160) {
t.Attributes = append(t.Attributes, Attribute{
Usage: Script,
Data: addr.BytesBE(),
})
}
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (t *Transaction) DecodeBinary(br *io.BinReader) { func (t *Transaction) DecodeBinary(br *io.BinReader) {
t.Type = TXType(br.ReadB()) t.Type = TXType(br.ReadB())

View file

@ -515,11 +515,7 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys
if err != nil { if err != nil {
return txHash, errors.Wrap(err, "failed to get address") return txHash, errors.Wrap(err, "failed to get address")
} }
tx.Attributes = append(tx.Attributes, tx.AddVerificationHash(addr)
transaction.Attribute{
Usage: transaction.Script,
Data: addr.BytesBE(),
})
} }
if err = acc.SignTx(tx); err != nil { if err = acc.SignTx(tx); err != nil {

View file

@ -38,11 +38,7 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac
if toAddressHash, err = address.StringToUint160(toAddress); err != nil { if toAddressHash, err = address.StringToUint160(toAddress); err != nil {
return nil, errs.Wrapf(err, "Failed to take script hash from address: %v", toAddress) return nil, errs.Wrapf(err, "Failed to take script hash from address: %v", toAddress)
} }
tx.Attributes = append(tx.Attributes, tx.AddVerificationHash(fromAddressHash)
transaction.Attribute{
Usage: transaction.Script,
Data: fromAddressHash.BytesBE(),
})
if err = AddInputsAndUnspentsToTx(tx, fromAddress, assetID, amount, balancer); err != nil { if err = AddInputsAndUnspentsToTx(tx, fromAddress, assetID, amount, balancer); err != nil {
return nil, errs.Wrap(err, "failed to add inputs and unspents to transaction") return nil, errs.Wrap(err, "failed to add inputs and unspents to transaction")