Merge pull request #1706 from rlan35/mainnet_release_1005_merge_s3
Mainnet release 1005 merge s3pull/1726/head
commit
cbb2d4997f
@ -0,0 +1,24 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"os" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
version string |
||||||
|
commit string |
||||||
|
builtAt string |
||||||
|
builtBy string |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
if os.Args[1] == "-version" { |
||||||
|
fmt.Fprintf(os.Stderr, versionS()+"\n") |
||||||
|
os.Exit(0) |
||||||
|
} |
||||||
|
if err := rootCmd.Execute(); err != nil { |
||||||
|
fmt.Println(err) |
||||||
|
os.Exit(-1) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,173 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"io/ioutil" |
||||||
|
"math/big" |
||||||
|
"net/http" |
||||||
|
"os" |
||||||
|
"path" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil" |
||||||
|
"github.com/ethereum/go-ethereum/rlp" |
||||||
|
"github.com/harmony-one/bls/ffi/go/bls" |
||||||
|
"github.com/harmony-one/harmony/accounts" |
||||||
|
"github.com/harmony-one/harmony/accounts/keystore" |
||||||
|
"github.com/harmony-one/harmony/internal/common" |
||||||
|
"github.com/harmony-one/harmony/shard" |
||||||
|
staking "github.com/harmony-one/harmony/staking/types" |
||||||
|
"github.com/spf13/cobra" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
keystoreDir = ".hmy/keystore" |
||||||
|
stakingRPC = "hmy_sendRawStakingTransaction" |
||||||
|
) |
||||||
|
|
||||||
|
type staker struct{} |
||||||
|
|
||||||
|
var ( |
||||||
|
queryID = 0 |
||||||
|
s = &staker{} |
||||||
|
localNetChain = big.NewInt(2) |
||||||
|
dAddr = common.ParseAddr(testAccount) |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// Harmony protocol assume beacon chain shard is only place to send
|
||||||
|
// staking, later need to consider logic when beacon chain shard rotates
|
||||||
|
stakingShard = 0 |
||||||
|
testAccount = "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9" |
||||||
|
testBLSPubKey = "b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611" |
||||||
|
testAccountPassword = "" |
||||||
|
) |
||||||
|
|
||||||
|
func (s *staker) run(cmd *cobra.Command, args []string) error { |
||||||
|
scryptN := keystore.StandardScryptN |
||||||
|
scryptP := keystore.StandardScryptP |
||||||
|
ks := keystore.NewKeyStore(keystoreDir, scryptN, scryptP) |
||||||
|
account := accounts.Account{Address: dAddr} |
||||||
|
ks.Unlock(account, testAccountPassword) |
||||||
|
gasPrice := big.NewInt(0) |
||||||
|
stakePayloadMaker := func() (staking.Directive, interface{}) { |
||||||
|
p := &bls.PublicKey{} |
||||||
|
p.DeserializeHexStr(testBLSPubKey) |
||||||
|
pub := shard.BlsPublicKey{} |
||||||
|
pub.FromLibBLSPublicKey(p) |
||||||
|
return staking.DirectiveNewValidator, staking.NewValidator{ |
||||||
|
Description: staking.Description{ |
||||||
|
Name: "something", |
||||||
|
Identity: "something else", |
||||||
|
Website: "some site, harmony.one", |
||||||
|
SecurityContact: "mr.smith", |
||||||
|
Details: "blah blah details", |
||||||
|
}, |
||||||
|
CommissionRates: staking.CommissionRates{ |
||||||
|
Rate: staking.NewDec(100), |
||||||
|
MaxRate: staking.NewDec(150), |
||||||
|
MaxChangeRate: staking.NewDec(5), |
||||||
|
}, |
||||||
|
MinSelfDelegation: big.NewInt(10), |
||||||
|
StakingAddress: common.Address(dAddr), |
||||||
|
PubKey: pub, |
||||||
|
Amount: big.NewInt(100), |
||||||
|
} |
||||||
|
// return message.DirectiveDelegate, message.Delegate{
|
||||||
|
// common.Address(dAddr),
|
||||||
|
// common.Address(dAddr),
|
||||||
|
// big.NewInt(10),
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
stakingTx, err := staking.NewStakingTransaction(2, 100, gasPrice, stakePayloadMaker) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
signed, oops := ks.SignStakingTx(account, stakingTx, localNetChain) |
||||||
|
if oops != nil { |
||||||
|
return oops |
||||||
|
} |
||||||
|
enc, oops1 := rlp.EncodeToBytes(signed) |
||||||
|
if oops1 != nil { |
||||||
|
return oops1 |
||||||
|
} |
||||||
|
tx := new(staking.StakingTransaction) |
||||||
|
if err := rlp.DecodeBytes(enc, tx); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
fmt.Printf("In Client side: %+v\n", tx) |
||||||
|
// return nil
|
||||||
|
rlp.DecodeBytes(enc, tx) |
||||||
|
hexSignature := hexutil.Encode(enc) |
||||||
|
param := []interface{}{hexSignature} |
||||||
|
result, reqOops := baseRequest(stakingRPC, "http://localhost:9500", param) |
||||||
|
fmt.Println(string(result)) |
||||||
|
return reqOops |
||||||
|
} |
||||||
|
|
||||||
|
func versionS() string { |
||||||
|
return fmt.Sprintf( |
||||||
|
"Harmony (C) 2019. %v, version %v-%v (%v %v)", |
||||||
|
path.Base(os.Args[0]), version, commit, builtBy, builtAt, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *staker) preRunInit(cmd *cobra.Command, args []string) error { |
||||||
|
// Just in case need to do some kind of setup that needs to propagate downward
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func baseRequest(method, node string, params interface{}) ([]byte, error) { |
||||||
|
requestBody, _ := json.Marshal(map[string]interface{}{ |
||||||
|
"jsonrpc": "2.0", |
||||||
|
"id": strconv.Itoa(queryID), |
||||||
|
"method": method, |
||||||
|
"params": params, |
||||||
|
}) |
||||||
|
resp, err := http.Post(node, "application/json", bytes.NewBuffer(requestBody)) |
||||||
|
fmt.Printf("URL: %s, Request Body: %s\n\n", node, string(requestBody)) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
body, err := ioutil.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
queryID++ |
||||||
|
fmt.Printf("URL: %s, Response Body: %s\n\n", node, string(body)) |
||||||
|
return body, err |
||||||
|
} |
||||||
|
|
||||||
|
func init() { |
||||||
|
|
||||||
|
rootCmd.AddCommand(&cobra.Command{ |
||||||
|
Use: "staking-iterate", |
||||||
|
Short: "run through staking process", |
||||||
|
PersistentPreRunE: s.preRunInit, |
||||||
|
RunE: s.run, |
||||||
|
}) |
||||||
|
|
||||||
|
rootCmd.AddCommand(&cobra.Command{ |
||||||
|
Use: "version", |
||||||
|
Short: "Show version", |
||||||
|
Run: func(cmd *cobra.Command, args []string) { |
||||||
|
fmt.Fprintf(os.Stderr, versionS()+"\n") |
||||||
|
os.Exit(0) |
||||||
|
}, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
rootCmd = &cobra.Command{ |
||||||
|
Use: "staking-standalone", |
||||||
|
SilenceUsage: true, |
||||||
|
Long: "testing staking quickly", |
||||||
|
Run: func(cmd *cobra.Command, args []string) { |
||||||
|
cmd.Help() |
||||||
|
}, |
||||||
|
} |
||||||
|
) |
@ -1,4 +1,4 @@ |
|||||||
package p2p |
package nodeconfig |
||||||
|
|
||||||
import "testing" |
import "testing" |
||||||
|
|
@ -0,0 +1,247 @@ |
|||||||
|
package types |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"math/big" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp" |
||||||
|
"github.com/harmony-one/harmony/internal/common" |
||||||
|
) |
||||||
|
|
||||||
|
// DVPair is struct that just has a delegator-validator pair with no other data.
|
||||||
|
// It is intended to be used as a marshalable pointer. For example, a DVPair can be used to construct the
|
||||||
|
// key to getting an UnbondingDelegation from state.
|
||||||
|
type DVPair struct { |
||||||
|
DelegatorAddress common.Address |
||||||
|
ValidatorAddress common.Address |
||||||
|
} |
||||||
|
|
||||||
|
// DVVTriplet is struct that just has a delegator-validator-validator triplet with no other data.
|
||||||
|
// It is intended to be used as a marshalable pointer. For example, a DVVTriplet can be used to construct the
|
||||||
|
// key to getting a Redelegation from state.
|
||||||
|
type DVVTriplet struct { |
||||||
|
DelegatorAddress common.Address |
||||||
|
ValidatorSrcAddress common.Address |
||||||
|
ValidatorDstAddress common.Address |
||||||
|
} |
||||||
|
|
||||||
|
// Delegation represents the bond with tokens held by an account. It is
|
||||||
|
// owned by one delegator, and is associated with the voting power of one
|
||||||
|
// validator.
|
||||||
|
type Delegation struct { |
||||||
|
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` |
||||||
|
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"` |
||||||
|
Amount *big.Int `json:"amount" yaml:"amount"` |
||||||
|
} |
||||||
|
|
||||||
|
// NewDelegation creates a new delegation object
|
||||||
|
func NewDelegation(delegatorAddr common.Address, validatorAddr common.Address, |
||||||
|
amount *big.Int) Delegation { |
||||||
|
|
||||||
|
return Delegation{ |
||||||
|
DelegatorAddress: delegatorAddr, |
||||||
|
ValidatorAddress: validatorAddr, |
||||||
|
Amount: amount, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// MarshalDelegation return the delegation
|
||||||
|
func MarshalDelegation(delegation Delegation) ([]byte, error) { |
||||||
|
return rlp.EncodeToBytes(delegation) |
||||||
|
} |
||||||
|
|
||||||
|
// UnmarshalDelegation return the delegation
|
||||||
|
func UnmarshalDelegation(by []byte) (*Delegation, error) { |
||||||
|
decoded := &Delegation{} |
||||||
|
err := rlp.DecodeBytes(by, decoded) |
||||||
|
return decoded, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetDelegatorAddr returns DelegatorAddr
|
||||||
|
func (d Delegation) GetDelegatorAddr() common.Address { return d.DelegatorAddress } |
||||||
|
|
||||||
|
// GetValidatorAddr returns ValidatorAddr
|
||||||
|
func (d Delegation) GetValidatorAddr() common.Address { return d.ValidatorAddress } |
||||||
|
|
||||||
|
// GetAmount returns amount of a delegation
|
||||||
|
func (d Delegation) GetAmount() *big.Int { return d.Amount } |
||||||
|
|
||||||
|
// String returns a human readable string representation of a Delegation.
|
||||||
|
func (d Delegation) String() string { |
||||||
|
return fmt.Sprintf(`Delegation: |
||||||
|
Delegator: %s |
||||||
|
Validator: %s |
||||||
|
Amount: %s`, d.DelegatorAddress, |
||||||
|
d.ValidatorAddress, d.Amount) |
||||||
|
} |
||||||
|
|
||||||
|
// Delegations is a collection of delegations
|
||||||
|
type Delegations []Delegation |
||||||
|
|
||||||
|
// String returns the string representation of a list of delegations
|
||||||
|
func (d Delegations) String() (out string) { |
||||||
|
for _, del := range d { |
||||||
|
out += del.String() + "\n" |
||||||
|
} |
||||||
|
return strings.TrimSpace(out) |
||||||
|
} |
||||||
|
|
||||||
|
// UnbondingDelegation stores all of a single delegator's unbonding bonds
|
||||||
|
// for a single validator in an time-ordered list
|
||||||
|
type UnbondingDelegation struct { |
||||||
|
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
|
||||||
|
ValidatorAddress common.Address `json:"validator_address" yaml:"validator_address"` // validator unbonding from operator addr
|
||||||
|
Entries []UnbondingDelegationEntry `json:"entries" yaml:"entries"` // unbonding delegation entries
|
||||||
|
} |
||||||
|
|
||||||
|
// UnbondingDelegationEntry - entry to an UnbondingDelegation
|
||||||
|
type UnbondingDelegationEntry struct { |
||||||
|
ExitEpoch *big.Int `json:"exit_epoch" yaml:"exit_epoch"` // epoch which the unbonding begins
|
||||||
|
Amount *big.Int `json:"amount" yaml:"amount"` // atoms to receive at completion
|
||||||
|
} |
||||||
|
|
||||||
|
// NewUnbondingDelegation - create a new unbonding delegation object
|
||||||
|
func NewUnbondingDelegation(delegatorAddr common.Address, |
||||||
|
validatorAddr common.Address, epoch *big.Int, amt *big.Int) UnbondingDelegation { |
||||||
|
|
||||||
|
entry := NewUnbondingDelegationEntry(epoch, amt) |
||||||
|
return UnbondingDelegation{ |
||||||
|
DelegatorAddress: delegatorAddr, |
||||||
|
ValidatorAddress: validatorAddr, |
||||||
|
Entries: []UnbondingDelegationEntry{entry}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewUnbondingDelegationEntry - create a new unbonding delegation object
|
||||||
|
func NewUnbondingDelegationEntry(epoch *big.Int, amt *big.Int) UnbondingDelegationEntry { |
||||||
|
return UnbondingDelegationEntry{ |
||||||
|
ExitEpoch: epoch, |
||||||
|
Amount: amt, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddEntry - append entry to the unbonding delegation
|
||||||
|
// if there exists same ExitEpoch entry, merge the amount
|
||||||
|
// TODO: check the total amount not exceed the staking amount call this function
|
||||||
|
func (d *UnbondingDelegation) AddEntry(epoch *big.Int, amt *big.Int) { |
||||||
|
entry := NewUnbondingDelegationEntry(epoch, amt) |
||||||
|
for i := range d.Entries { |
||||||
|
if d.Entries[i].ExitEpoch == entry.ExitEpoch { |
||||||
|
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
// same exit epoch entry not found
|
||||||
|
d.Entries = append(d.Entries, entry) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// String returns a human readable string representation of an UnbondingDelegation.
|
||||||
|
func (d UnbondingDelegation) String() string { |
||||||
|
out := fmt.Sprintf(`Unbonding Delegations between: |
||||||
|
Delegator: %s |
||||||
|
Validator: %s |
||||||
|
Entries:`, d.DelegatorAddress, d.ValidatorAddress) |
||||||
|
for i, entry := range d.Entries { |
||||||
|
out += fmt.Sprintf(` Unbonding Delegation %d: |
||||||
|
ExitEpoch: %v |
||||||
|
Amount: %s`, i, entry.ExitEpoch, entry.Amount) |
||||||
|
} |
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// UnbondingDelegations is a collection of UnbondingDelegation
|
||||||
|
type UnbondingDelegations []UnbondingDelegation |
||||||
|
|
||||||
|
func (ubds UnbondingDelegations) String() (out string) { |
||||||
|
for _, u := range ubds { |
||||||
|
out += u.String() + "\n" |
||||||
|
} |
||||||
|
return strings.TrimSpace(out) |
||||||
|
} |
||||||
|
|
||||||
|
// Redelegation contains the list of a particular delegator's
|
||||||
|
// redelegating bonds from a particular source validator to a
|
||||||
|
// particular destination validator
|
||||||
|
type Redelegation struct { |
||||||
|
DelegatorAddress common.Address `json:"delegator_address" yaml:"delegator_address"` // delegator
|
||||||
|
ValidatorSrcAddress common.Address `json:"validator_src_address" yaml:"validator_src_address"` // validator redelegation source operator addr
|
||||||
|
ValidatorDstAddress common.Address `json:"validator_dst_address" yaml:"validator_dst_address"` // validator redelegation destination operator addr
|
||||||
|
Entries []RedelegationEntry `json:"entries" yaml:"entries"` // redelegation entries
|
||||||
|
} |
||||||
|
|
||||||
|
// RedelegationEntry - entry to a Redelegation
|
||||||
|
type RedelegationEntry struct { |
||||||
|
Epoch *big.Int `json:"epoch" yaml:"epoch"` // epoch at which the redelegation took place
|
||||||
|
Amount *big.Int `json:"amount" yaml:"amount"` // amount of destination-validator tokens created by redelegation
|
||||||
|
} |
||||||
|
|
||||||
|
// NewRedelegation - create a new redelegation object
|
||||||
|
func NewRedelegation(delegatorAddr common.Address, validatorSrcAddr, |
||||||
|
validatorDstAddr common.Address, epoch *big.Int, amt *big.Int) Redelegation { |
||||||
|
entry := NewRedelegationEntry(epoch, amt) |
||||||
|
return Redelegation{ |
||||||
|
DelegatorAddress: delegatorAddr, |
||||||
|
ValidatorSrcAddress: validatorSrcAddr, |
||||||
|
ValidatorDstAddress: validatorDstAddr, |
||||||
|
Entries: []RedelegationEntry{entry}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewRedelegationEntry - create a new redelegation object
|
||||||
|
func NewRedelegationEntry(epoch *big.Int, amt *big.Int) RedelegationEntry { |
||||||
|
return RedelegationEntry{ |
||||||
|
Epoch: epoch, |
||||||
|
Amount: amt, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddEntry - append entry to the unbonding delegation
|
||||||
|
// Merge if has same epoch field
|
||||||
|
func (d *Redelegation) AddEntry(epoch *big.Int, amt *big.Int) { |
||||||
|
entry := NewRedelegationEntry(epoch, amt) |
||||||
|
|
||||||
|
for i := range d.Entries { |
||||||
|
if d.Entries[i].Epoch == entry.Epoch { |
||||||
|
d.Entries[i].Amount.Add(d.Entries[i].Amount, entry.Amount) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
// same epoch entry not found
|
||||||
|
d.Entries = append(d.Entries, entry) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// String returns a human readable string representation of a Redelegation.
|
||||||
|
func (d Redelegation) String() string { |
||||||
|
out := fmt.Sprintf(`Redelegations between: |
||||||
|
Delegator: %s |
||||||
|
Source Validator: %s |
||||||
|
Destination Validator: %s |
||||||
|
Entries: |
||||||
|
`, |
||||||
|
d.DelegatorAddress, d.ValidatorSrcAddress, d.ValidatorDstAddress, |
||||||
|
) |
||||||
|
|
||||||
|
for i, entry := range d.Entries { |
||||||
|
out += fmt.Sprintf(` Redelegation Entry #%d: |
||||||
|
Epoch: %v |
||||||
|
Amount: %v |
||||||
|
`, |
||||||
|
i, entry.Epoch, entry.Amount, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
return strings.TrimRight(out, "\n") |
||||||
|
} |
||||||
|
|
||||||
|
// Redelegations are a collection of Redelegation
|
||||||
|
type Redelegations []Redelegation |
||||||
|
|
||||||
|
func (d Redelegations) String() (out string) { |
||||||
|
for _, red := range d { |
||||||
|
out += red.String() + "\n" |
||||||
|
} |
||||||
|
return strings.TrimSpace(out) |
||||||
|
} |
@ -1,218 +1,207 @@ |
|||||||
package types |
package types |
||||||
|
|
||||||
import ( |
// var (
|
||||||
"math/big" |
// minSelfDelegation = big.NewInt(1000)
|
||||||
"reflect" |
// stakeAmount = big.NewInt(2000)
|
||||||
"testing" |
// delegateAmount = big.NewInt(500)
|
||||||
|
// validatorAddress = common.Address(common.MustBech32ToAddress("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy"))
|
||||||
"github.com/ethereum/go-ethereum/rlp" |
// validatorAddress2 = common.Address(common.MustBech32ToAddress("one1d2rngmem4x2c6zxsjjz29dlah0jzkr0k2n88wc"))
|
||||||
"github.com/harmony-one/harmony/crypto/bls" |
// delegatorAddress = common.Address(common.MustBech32ToAddress("one16qsd5ant9v94jrs89mruzx62h7ekcfxmduh2rx"))
|
||||||
"github.com/harmony-one/harmony/internal/common" |
// blsPubKey = bls.RandPrivateKey().GetPublicKey()
|
||||||
"github.com/harmony-one/harmony/shard" |
// )
|
||||||
) |
|
||||||
|
// func TestMsgCreateValidatorRLP(t *testing.T) {
|
||||||
var ( |
// commissionRate := NewDecWithPrec(1, 2) // 10%
|
||||||
minSelfDelegation = big.NewInt(1000) |
// maxRate := NewDecWithPrec(2, 2) // 20%
|
||||||
stakeAmount = big.NewInt(2000) |
// maxChangeRate := NewDecWithPrec(1, 3) // 1%
|
||||||
delegateAmount = big.NewInt(500) |
|
||||||
validatorAddress = common.MustBech32ToAddress("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") |
// blsPublickey := shard.BlsPublicKey{}
|
||||||
validatorAddress2 = common.MustBech32ToAddress("one1d2rngmem4x2c6zxsjjz29dlah0jzkr0k2n88wc") |
// blsPublickey.FromLibBLSPublicKey(blsPubKey)
|
||||||
delegatorAddress = common.MustBech32ToAddress("one16qsd5ant9v94jrs89mruzx62h7ekcfxmduh2rx") |
|
||||||
blsPubKey = bls.RandPrivateKey().GetPublicKey() |
// msgCreateValidator := NewMsgCreateValidator(Description{
|
||||||
) |
// Name: "validator 1",
|
||||||
|
// Identity: "1",
|
||||||
func TestMsgCreateValidatorRLP(t *testing.T) { |
// Website: "harmony.one",
|
||||||
commissionRate := NewDecWithPrec(1, 2) // 10%
|
// SecurityContact: "11.111.1111",
|
||||||
maxRate := NewDecWithPrec(2, 2) // 20%
|
// Details: "the best validator ever",
|
||||||
maxChangeRate := NewDecWithPrec(1, 3) // 1%
|
// }, CommissionRates{
|
||||||
|
// Rate: commissionRate,
|
||||||
blsPublickey := shard.BlsPublicKey{} |
// MaxRate: maxRate,
|
||||||
blsPublickey.FromLibBLSPublicKey(blsPubKey) |
// MaxChangeRate: maxChangeRate,
|
||||||
|
// }, minSelfDelegation, validatorAddress, blsPublickey, stakeAmount)
|
||||||
msgCreateValidator := NewMsgCreateValidator(Description{ |
|
||||||
Name: "validator 1", |
// rlpBytes, err := rlp.EncodeToBytes(msgCreateValidator)
|
||||||
Identity: "1", |
// if err != nil {
|
||||||
Website: "harmony.one", |
// t.Error("failed to rlp encode 'create validator' message")
|
||||||
SecurityContact: "11.111.1111", |
// }
|
||||||
Details: "the best validator ever", |
|
||||||
}, CommissionRates{ |
// decodedMsg := &MsgCreateValidator{}
|
||||||
Rate: commissionRate, |
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
|
||||||
MaxRate: maxRate, |
|
||||||
MaxChangeRate: maxChangeRate, |
// if err != nil {
|
||||||
}, minSelfDelegation, validatorAddress, blsPublickey, stakeAmount) |
// t.Error("failed to rlp decode 'create validator' message")
|
||||||
|
// }
|
||||||
rlpBytes, err := rlp.EncodeToBytes(msgCreateValidator) |
|
||||||
if err != nil { |
// if !decodedMsg.Commission.Rate.Equal(msgCreateValidator.Commission.Rate) {
|
||||||
t.Error("failed to rlp encode 'create validator' message") |
// t.Error("Commission rate does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
decodedMsg := &MsgCreateValidator{} |
// if !decodedMsg.Commission.MaxRate.Equal(msgCreateValidator.Commission.MaxRate) {
|
||||||
err = rlp.DecodeBytes(rlpBytes, decodedMsg) |
// t.Error("MaxRate does not match")
|
||||||
|
// }
|
||||||
if err != nil { |
|
||||||
t.Error("failed to rlp decode 'create validator' message") |
// if !decodedMsg.Commission.MaxChangeRate.Equal(msgCreateValidator.Commission.MaxChangeRate) {
|
||||||
} |
// t.Error("MaxChangeRate does not match")
|
||||||
|
// }
|
||||||
if !decodedMsg.Commission.Rate.Equal(msgCreateValidator.Commission.Rate) { |
|
||||||
t.Error("Commission rate does not match") |
// if !reflect.DeepEqual(decodedMsg.Description, msgCreateValidator.Description) {
|
||||||
} |
// t.Error("Description does not match")
|
||||||
|
// }
|
||||||
if !decodedMsg.Commission.MaxRate.Equal(msgCreateValidator.Commission.MaxRate) { |
|
||||||
t.Error("MaxRate does not match") |
// if decodedMsg.MinSelfDelegation.Cmp(msgCreateValidator.MinSelfDelegation) != 0 {
|
||||||
} |
// t.Error("MinSelfDelegation does not match")
|
||||||
|
// }
|
||||||
if !decodedMsg.Commission.MaxChangeRate.Equal(msgCreateValidator.Commission.MaxChangeRate) { |
|
||||||
t.Error("MaxChangeRate does not match") |
// if decodedMsg.StakingAddress.String() != msgCreateValidator.StakingAddress.String() {
|
||||||
} |
// t.Error("StakingAddress does not match")
|
||||||
|
// }
|
||||||
if !reflect.DeepEqual(decodedMsg.Description, msgCreateValidator.Description) { |
|
||||||
t.Error("Description does not match") |
// if shard.CompareBlsPublicKey(decodedMsg.ValidatingPubKey, msgCreateValidator.ValidatingPubKey) != 0 {
|
||||||
} |
// t.Error("ValidatingPubKey does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.MinSelfDelegation.Cmp(msgCreateValidator.MinSelfDelegation) != 0 { |
|
||||||
t.Error("MinSelfDelegation does not match") |
// if decodedMsg.Amount.Cmp(msgCreateValidator.Amount) != 0 {
|
||||||
} |
// t.Error("Amount does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.StakingAddress.Hex() != msgCreateValidator.StakingAddress.Hex() { |
// }
|
||||||
t.Error("StakingAddress does not match") |
|
||||||
} |
// func TestMsgEditValidatorRLP(t *testing.T) {
|
||||||
|
// commissionRate := NewDecWithPrec(1, 2) // 10%
|
||||||
if shard.CompareBlsPublicKey(decodedMsg.ValidatingPubKey, msgCreateValidator.ValidatingPubKey) != 0 { |
|
||||||
t.Error("ValidatingPubKey does not match") |
// blsPublickey := shard.BlsPublicKey{}
|
||||||
} |
// blsPublickey.FromLibBLSPublicKey(blsPubKey)
|
||||||
|
|
||||||
if decodedMsg.Amount.Cmp(msgCreateValidator.Amount) != 0 { |
// msgEditValidator := NewMsgEditValidator(Description{
|
||||||
t.Error("Amount does not match") |
// Name: "validator 1",
|
||||||
} |
// Identity: "1",
|
||||||
} |
// Website: "harmony.one",
|
||||||
|
// SecurityContact: "11.111.1111",
|
||||||
func TestMsgEditValidatorRLP(t *testing.T) { |
// Details: "the best validator ever",
|
||||||
commissionRate := NewDecWithPrec(1, 2) // 10%
|
// }, validatorAddress, commissionRate, minSelfDelegation)
|
||||||
|
|
||||||
blsPublickey := shard.BlsPublicKey{} |
// rlpBytes, err := rlp.EncodeToBytes(msgEditValidator)
|
||||||
blsPublickey.FromLibBLSPublicKey(blsPubKey) |
// if err != nil {
|
||||||
|
// t.Error("failed to rlp encode 'create validator' message")
|
||||||
msgEditValidator := NewMsgEditValidator(Description{ |
// }
|
||||||
Name: "validator 1", |
|
||||||
Identity: "1", |
// decodedMsg := &MsgEditValidator{}
|
||||||
Website: "harmony.one", |
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
|
||||||
SecurityContact: "11.111.1111", |
|
||||||
Details: "the best validator ever", |
// if err != nil {
|
||||||
}, validatorAddress, commissionRate, minSelfDelegation) |
// t.Error("failed to rlp decode 'create validator' message")
|
||||||
|
// }
|
||||||
rlpBytes, err := rlp.EncodeToBytes(msgEditValidator) |
|
||||||
if err != nil { |
// if !reflect.DeepEqual(decodedMsg.Description, msgEditValidator.Description) {
|
||||||
t.Error("failed to rlp encode 'create validator' message") |
// t.Error("Description does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
decodedMsg := &MsgEditValidator{} |
// if decodedMsg.StakingAddress.String() != msgEditValidator.StakingAddress.String() {
|
||||||
err = rlp.DecodeBytes(rlpBytes, decodedMsg) |
// t.Error("StakingAddress does not match")
|
||||||
|
// }
|
||||||
if err != nil { |
|
||||||
t.Error("failed to rlp decode 'create validator' message") |
// if !decodedMsg.CommissionRate.Equal(msgEditValidator.CommissionRate) {
|
||||||
} |
// t.Error("Commission rate does not match")
|
||||||
|
// }
|
||||||
if !reflect.DeepEqual(decodedMsg.Description, msgEditValidator.Description) { |
|
||||||
t.Error("Description does not match") |
// if decodedMsg.MinSelfDelegation.Cmp(msgEditValidator.MinSelfDelegation) != 0 {
|
||||||
} |
// t.Error("MinSelfDelegation does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.StakingAddress.Hex() != msgEditValidator.StakingAddress.Hex() { |
// }
|
||||||
t.Error("StakingAddress does not match") |
|
||||||
} |
// func TestMsgDelegateRLP(t *testing.T) {
|
||||||
|
// msgDelegate := NewMsgDelegate(delegatorAddress, validatorAddress, delegateAmount)
|
||||||
if !decodedMsg.CommissionRate.Equal(msgEditValidator.CommissionRate) { |
|
||||||
t.Error("Commission rate does not match") |
// rlpBytes, err := rlp.EncodeToBytes(msgDelegate)
|
||||||
} |
// if err != nil {
|
||||||
|
// t.Error("failed to rlp encode 'create validator' message")
|
||||||
if decodedMsg.MinSelfDelegation.Cmp(msgEditValidator.MinSelfDelegation) != 0 { |
// }
|
||||||
t.Error("MinSelfDelegation does not match") |
|
||||||
} |
// decodedMsg := &MsgDelegate{}
|
||||||
} |
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
|
||||||
|
|
||||||
func TestMsgDelegateRLP(t *testing.T) { |
// if err != nil {
|
||||||
msgDelegate := NewMsgDelegate(delegatorAddress, validatorAddress, delegateAmount) |
// t.Error("failed to rlp decode 'create validator' message")
|
||||||
|
// }
|
||||||
rlpBytes, err := rlp.EncodeToBytes(msgDelegate) |
|
||||||
if err != nil { |
// if decodedMsg.DelegatorAddress.String() != msgDelegate.DelegatorAddress.String() {
|
||||||
t.Error("failed to rlp encode 'create validator' message") |
// t.Error("DelegatorAddress does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
decodedMsg := &MsgDelegate{} |
// if decodedMsg.ValidatorAddress.String() != msgDelegate.ValidatorAddress.String() {
|
||||||
err = rlp.DecodeBytes(rlpBytes, decodedMsg) |
// t.Error("ValidatorAddress does not match")
|
||||||
|
// }
|
||||||
if err != nil { |
|
||||||
t.Error("failed to rlp decode 'create validator' message") |
// if decodedMsg.Amount.Cmp(msgDelegate.Amount) != 0 {
|
||||||
} |
// t.Error("Amount does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.DelegatorAddress.Hex() != msgDelegate.DelegatorAddress.Hex() { |
// }
|
||||||
t.Error("DelegatorAddress does not match") |
|
||||||
} |
// func TestMsgRedelegateRLP(t *testing.T) {
|
||||||
|
// msgRedelegate := NewMsgRedelegate(delegatorAddress, validatorAddress, validatorAddress2, delegateAmount)
|
||||||
if decodedMsg.ValidatorAddress.Hex() != msgDelegate.ValidatorAddress.Hex() { |
|
||||||
t.Error("ValidatorAddress does not match") |
// rlpBytes, err := rlp.EncodeToBytes(msgRedelegate)
|
||||||
} |
// if err != nil {
|
||||||
|
// t.Error("failed to rlp encode 'create validator' message")
|
||||||
if decodedMsg.Amount.Cmp(msgDelegate.Amount) != 0 { |
// }
|
||||||
t.Error("Amount does not match") |
|
||||||
} |
// decodedMsg := &MsgRedelegate{}
|
||||||
} |
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
|
||||||
|
|
||||||
func TestMsgRedelegateRLP(t *testing.T) { |
// if err != nil {
|
||||||
msgRedelegate := NewMsgRedelegate(delegatorAddress, validatorAddress, validatorAddress2, delegateAmount) |
// t.Error("failed to rlp decode 'create validator' message")
|
||||||
|
// }
|
||||||
rlpBytes, err := rlp.EncodeToBytes(msgRedelegate) |
|
||||||
if err != nil { |
// if decodedMsg.DelegatorAddress.String() != msgRedelegate.DelegatorAddress.String() {
|
||||||
t.Error("failed to rlp encode 'create validator' message") |
// t.Error("DelegatorAddress does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
decodedMsg := &MsgRedelegate{} |
// if decodedMsg.ValidatorSrcAddress.String() != msgRedelegate.ValidatorSrcAddress.String() {
|
||||||
err = rlp.DecodeBytes(rlpBytes, decodedMsg) |
// t.Error("ValidatorSrcAddress does not match")
|
||||||
|
// }
|
||||||
if err != nil { |
|
||||||
t.Error("failed to rlp decode 'create validator' message") |
// if decodedMsg.ValidatorDstAddress.String() != msgRedelegate.ValidatorDstAddress.String() {
|
||||||
} |
// t.Error("ValidatorDstAddress does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.DelegatorAddress.Hex() != msgRedelegate.DelegatorAddress.Hex() { |
|
||||||
t.Error("DelegatorAddress does not match") |
// if decodedMsg.Amount.Cmp(msgRedelegate.Amount) != 0 {
|
||||||
} |
// t.Error("Amount does not match")
|
||||||
|
// }
|
||||||
if decodedMsg.ValidatorSrcAddress.Hex() != msgRedelegate.ValidatorSrcAddress.Hex() { |
// }
|
||||||
t.Error("ValidatorSrcAddress does not match") |
|
||||||
} |
// func TestMsgUndelegateRLP(t *testing.T) {
|
||||||
|
// msgUndelegate := NewMsgUndelegate(delegatorAddress, validatorAddress, delegateAmount)
|
||||||
if decodedMsg.ValidatorDstAddress.Hex() != msgRedelegate.ValidatorDstAddress.Hex() { |
|
||||||
t.Error("ValidatorDstAddress does not match") |
// rlpBytes, err := rlp.EncodeToBytes(msgUndelegate)
|
||||||
} |
// if err != nil {
|
||||||
|
// t.Error("failed to rlp encode 'create validator' message")
|
||||||
if decodedMsg.Amount.Cmp(msgRedelegate.Amount) != 0 { |
// }
|
||||||
t.Error("Amount does not match") |
|
||||||
} |
// decodedMsg := &MsgUndelegate{}
|
||||||
} |
// err = rlp.DecodeBytes(rlpBytes, decodedMsg)
|
||||||
|
|
||||||
func TestMsgUndelegateRLP(t *testing.T) { |
|
||||||
msgUndelegate := NewMsgUndelegate(delegatorAddress, validatorAddress, delegateAmount) |
|
||||||
|
|
||||||
rlpBytes, err := rlp.EncodeToBytes(msgUndelegate) |
|
||||||
if err != nil { |
|
||||||
t.Error("failed to rlp encode 'create validator' message") |
|
||||||
} |
|
||||||
|
|
||||||
decodedMsg := &MsgUndelegate{} |
|
||||||
err = rlp.DecodeBytes(rlpBytes, decodedMsg) |
|
||||||
|
|
||||||
if err != nil { |
// if err != nil {
|
||||||
t.Error("failed to rlp decode 'create validator' message") |
// t.Error("failed to rlp decode 'create validator' message")
|
||||||
} |
// }
|
||||||
|
|
||||||
if decodedMsg.DelegatorAddress.Hex() != msgUndelegate.DelegatorAddress.Hex() { |
// if decodedMsg.DelegatorAddress.String() != msgUndelegate.DelegatorAddress.String() {
|
||||||
t.Error("DelegatorAddress does not match") |
// t.Error("DelegatorAddress does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
if decodedMsg.ValidatorAddress.Hex() != msgUndelegate.ValidatorAddress.Hex() { |
// if decodedMsg.ValidatorAddress.String() != msgUndelegate.ValidatorAddress.String() {
|
||||||
t.Error("ValidatorAddress does not match") |
// t.Error("ValidatorAddress does not match")
|
||||||
} |
// }
|
||||||
|
|
||||||
if decodedMsg.Amount.Cmp(msgUndelegate.Amount) != 0 { |
// if decodedMsg.Amount.Cmp(msgUndelegate.Amount) != 0 {
|
||||||
t.Error("Amount does not match") |
// t.Error("Amount does not match")
|
||||||
} |
// }
|
||||||
} |
// }
|
||||||
|
@ -0,0 +1,199 @@ |
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types |
||||||
|
|
||||||
|
import ( |
||||||
|
"crypto/ecdsa" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"math/big" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common" |
||||||
|
"github.com/ethereum/go-ethereum/crypto" |
||||||
|
"github.com/harmony-one/harmony/core" |
||||||
|
"github.com/harmony-one/harmony/crypto/hash" |
||||||
|
) |
||||||
|
|
||||||
|
// sigCache is used to cache the derived sender and contains
|
||||||
|
// the signer used to derive it.
|
||||||
|
type sigCache struct { |
||||||
|
signer Signer |
||||||
|
from common.Address |
||||||
|
} |
||||||
|
|
||||||
|
// Sign signs the stake using the given signer and private key
|
||||||
|
func Sign(tx *StakingTransaction, s Signer, prv *ecdsa.PrivateKey) (*StakingTransaction, error) { |
||||||
|
h := s.Hash(tx) |
||||||
|
sig, err := crypto.Sign(h[:], prv) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return tx.WithSignature(s, sig) |
||||||
|
} |
||||||
|
|
||||||
|
// Sender returns the address derived from the signature (V, R, S) using secp256k1
|
||||||
|
// elliptic curve and an error if it failed deriving or upon an incorrect
|
||||||
|
// signature.
|
||||||
|
//
|
||||||
|
// Sender may cache the address, allowing it to be used regardless of
|
||||||
|
// signing method. The cache is invalidated if the cached signer does
|
||||||
|
// not match the signer used in the current call.
|
||||||
|
func Sender(signer Signer, tx *StakingTransaction) (common.Address, error) { |
||||||
|
if sc := tx.from.Load(); sc != nil { |
||||||
|
sigCache := sc.(sigCache) |
||||||
|
// If the signer used to derive from in a previous
|
||||||
|
// call is not the same as used current, invalidate
|
||||||
|
// the cache.
|
||||||
|
if sigCache.signer.Equal(signer) { |
||||||
|
return sigCache.from, nil |
||||||
|
} |
||||||
|
} |
||||||
|
addr, err := signer.Sender(tx) |
||||||
|
if err != nil { |
||||||
|
return common.Address{}, err |
||||||
|
} |
||||||
|
tx.from.Store(sigCache{signer: signer, from: addr}) |
||||||
|
return addr, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Signer encapsulates transaction signature handling. Note that this interface is not a
|
||||||
|
// stable API and may change at any time to accommodate new protocol rules.
|
||||||
|
type Signer interface { |
||||||
|
// Sender returns the sender address of the transaction.
|
||||||
|
Sender(tx *StakingTransaction) (common.Address, error) |
||||||
|
// SignatureValues returns the raw R, S, V values corresponding to the
|
||||||
|
// given signature.
|
||||||
|
SignatureValues(tx *StakingTransaction, sig []byte) (r, s, v *big.Int, err error) |
||||||
|
// Hash returns the hash to be signed.
|
||||||
|
Hash(tx *StakingTransaction) common.Hash |
||||||
|
// Equal returns true if the given signer is the same as the receiver.
|
||||||
|
Equal(s Signer) bool |
||||||
|
} |
||||||
|
|
||||||
|
// EIP155Signer implements Signer using the EIP155 rules.
|
||||||
|
type EIP155Signer struct { |
||||||
|
chainID, chainIDMul *big.Int |
||||||
|
} |
||||||
|
|
||||||
|
// NewEIP155Signer creates a EIP155Signer given chainID.
|
||||||
|
func NewEIP155Signer(chainID *big.Int) EIP155Signer { |
||||||
|
if chainID == nil { |
||||||
|
chainID = new(big.Int) |
||||||
|
} |
||||||
|
return EIP155Signer{ |
||||||
|
chainID: chainID, |
||||||
|
chainIDMul: new(big.Int).Mul(chainID, big.NewInt(2)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Equal checks if the given EIP155Signer is equal to another Signer.
|
||||||
|
func (s EIP155Signer) Equal(s2 Signer) bool { |
||||||
|
eip155, ok := s2.(EIP155Signer) |
||||||
|
return ok && eip155.chainID.Cmp(s.chainID) == 0 |
||||||
|
} |
||||||
|
|
||||||
|
var big8 = big.NewInt(8) |
||||||
|
|
||||||
|
// Sender returns the sender address of the given signer.
|
||||||
|
func (s EIP155Signer) Sender(tx *StakingTransaction) (common.Address, error) { |
||||||
|
if tx.ChainID().Cmp(s.chainID) != 0 { |
||||||
|
return common.Address{}, core.ErrInvalidChainID |
||||||
|
} |
||||||
|
V := new(big.Int).Sub(tx.data.V, s.chainIDMul) |
||||||
|
V.Sub(V, big8) |
||||||
|
return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true) |
||||||
|
} |
||||||
|
|
||||||
|
// SignatureValues returns signature values. This signature
|
||||||
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
||||||
|
func (s EIP155Signer) SignatureValues( |
||||||
|
tx *StakingTransaction, sig []byte, |
||||||
|
) (R, S, V *big.Int, err error) { |
||||||
|
sigValues := func(tx *StakingTransaction, sig []byte) (r, s, v *big.Int, err error) { |
||||||
|
if len(sig) != 65 { |
||||||
|
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig))) |
||||||
|
} |
||||||
|
r = new(big.Int).SetBytes(sig[:32]) |
||||||
|
s = new(big.Int).SetBytes(sig[32:64]) |
||||||
|
v = new(big.Int).SetBytes([]byte{sig[64] + 27}) |
||||||
|
return r, s, v, nil |
||||||
|
} |
||||||
|
R, S, V, err = sigValues(tx, sig) |
||||||
|
if err != nil { |
||||||
|
return nil, nil, nil, err |
||||||
|
} |
||||||
|
if s.chainID.Sign() != 0 { |
||||||
|
V = big.NewInt(int64(sig[64] + 35)) |
||||||
|
V.Add(V, s.chainIDMul) |
||||||
|
} |
||||||
|
return R, S, V, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Hash returns the hash to be signed by the sender.
|
||||||
|
// It does not uniquely identify the transaction.
|
||||||
|
func (s EIP155Signer) Hash(tx *StakingTransaction) common.Hash { |
||||||
|
return hash.FromRLP([]interface{}{ |
||||||
|
tx.data.Directive, |
||||||
|
tx.data.StakeMsg, |
||||||
|
tx.data.AccountNonce, |
||||||
|
tx.data.Price, |
||||||
|
tx.data.GasLimit, |
||||||
|
s.chainID, uint(0), uint(0), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func recoverPlain( |
||||||
|
sighash common.Hash, R, S, Vb *big.Int, homestead bool, |
||||||
|
) (common.Address, error) { |
||||||
|
if Vb.BitLen() > 8 { |
||||||
|
return common.Address{}, ErrInvalidSig |
||||||
|
} |
||||||
|
V := byte(Vb.Uint64() - 27) |
||||||
|
if !crypto.ValidateSignatureValues(V, R, S, homestead) { |
||||||
|
return common.Address{}, ErrInvalidSig |
||||||
|
} |
||||||
|
// encode the signature in uncompressed format
|
||||||
|
r, s := R.Bytes(), S.Bytes() |
||||||
|
sig := make([]byte, 65) |
||||||
|
copy(sig[32-len(r):32], r) |
||||||
|
copy(sig[64-len(s):64], s) |
||||||
|
sig[64] = V |
||||||
|
// recover the public key from the signature
|
||||||
|
pub, err := crypto.Ecrecover(sighash[:], sig) |
||||||
|
if err != nil { |
||||||
|
return common.Address{}, err |
||||||
|
} |
||||||
|
if len(pub) == 0 || pub[0] != 4 { |
||||||
|
return common.Address{}, errors.New("invalid public key") |
||||||
|
} |
||||||
|
var addr common.Address |
||||||
|
copy(addr[:], crypto.Keccak256(pub[1:])[12:]) |
||||||
|
return addr, nil |
||||||
|
} |
||||||
|
|
||||||
|
// deriveChainID derives the chain id from the given v parameter
|
||||||
|
func deriveChainID(v *big.Int) *big.Int { |
||||||
|
if v.BitLen() <= 64 { |
||||||
|
v := v.Uint64() |
||||||
|
if v == 27 || v == 28 { |
||||||
|
return new(big.Int) |
||||||
|
} |
||||||
|
return new(big.Int).SetUint64((v - 35) / 2) |
||||||
|
} |
||||||
|
v = new(big.Int).Sub(v, big.NewInt(35)) |
||||||
|
return v.Div(v, big.NewInt(2)) |
||||||
|
} |
@ -1,39 +0,0 @@ |
|||||||
package types |
|
||||||
|
|
||||||
import ( |
|
||||||
"bytes" |
|
||||||
"math/big" |
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common" |
|
||||||
"github.com/harmony-one/harmony/crypto/hash" |
|
||||||
) |
|
||||||
|
|
||||||
// StakingTransaction struct.
|
|
||||||
type StakingTransaction struct { |
|
||||||
AccountNonce uint64 `json:"nonce" gencodec:"required"` |
|
||||||
Price *big.Int `json:"gasPrice" gencodec:"required"` |
|
||||||
GasLimit uint64 `json:"gas" gencodec:"required"` |
|
||||||
Msg StakingMessage `json:"msg" gencodec:"required"` |
|
||||||
|
|
||||||
// Signature values
|
|
||||||
V *big.Int `json:"v" gencodec:"required"` |
|
||||||
R *big.Int `json:"r" gencodec:"required"` |
|
||||||
S *big.Int `json:"s" gencodec:"required"` |
|
||||||
|
|
||||||
// This is only used when marshaling to JSON.
|
|
||||||
hash *common.Hash `json:"hash" rlp:"-"` |
|
||||||
} |
|
||||||
|
|
||||||
// StakingTransactions is a Transaction slice type for basic sorting.
|
|
||||||
type StakingTransactions []*StakingTransaction |
|
||||||
|
|
||||||
// Hash hashes the RLP encoding of tx.
|
|
||||||
// It uniquely identifies the transaction.
|
|
||||||
func (tx *StakingTransaction) Hash() common.Hash { |
|
||||||
emptyHash := common.Hash{} |
|
||||||
if bytes.Compare(tx.hash[:], emptyHash[:]) == 0 { |
|
||||||
h := hash.FromRLP(tx) |
|
||||||
tx.hash = &h |
|
||||||
} |
|
||||||
return *tx.hash |
|
||||||
} |
|
@ -0,0 +1,110 @@ |
|||||||
|
package types |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"io" |
||||||
|
"math/big" |
||||||
|
"sync/atomic" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common" |
||||||
|
"github.com/ethereum/go-ethereum/rlp" |
||||||
|
"github.com/harmony-one/harmony/crypto/hash" |
||||||
|
) |
||||||
|
|
||||||
|
type txdata struct { |
||||||
|
Directive |
||||||
|
StakeMsg interface{} |
||||||
|
AccountNonce uint64 `json:"nonce" gencodec:"required"` |
||||||
|
Price *big.Int `json:"gasPrice" gencodec:"required"` |
||||||
|
GasLimit uint64 `json:"gas" gencodec:"required"` |
||||||
|
// Signature values
|
||||||
|
V *big.Int `json:"v" gencodec:"required"` |
||||||
|
R *big.Int `json:"r" gencodec:"required"` |
||||||
|
S *big.Int `json:"s" gencodec:"required"` |
||||||
|
// This is only used when marshaling to JSON.
|
||||||
|
Hash *common.Hash `json:"hash" rlp:"-"` |
||||||
|
} |
||||||
|
|
||||||
|
// StakingTransaction is a record captuing all staking operations
|
||||||
|
type StakingTransaction struct { |
||||||
|
data txdata |
||||||
|
// caches
|
||||||
|
hash atomic.Value |
||||||
|
size atomic.Value |
||||||
|
from atomic.Value |
||||||
|
} |
||||||
|
|
||||||
|
type fulfill func() (Directive, interface{}) |
||||||
|
|
||||||
|
// NewStakingTransaction produces a new staking transaction record
|
||||||
|
func NewStakingTransaction( |
||||||
|
nonce, gasLimit uint64, gasPrice *big.Int, f fulfill, |
||||||
|
) (*StakingTransaction, error) { |
||||||
|
directive, payload := f() |
||||||
|
// TODO(Double check that this is legitmate directive)
|
||||||
|
newStake := &StakingTransaction{data: txdata{ |
||||||
|
directive, |
||||||
|
payload, |
||||||
|
nonce, |
||||||
|
big.NewInt(0).Set(gasPrice), |
||||||
|
gasLimit, |
||||||
|
big.NewInt(0), |
||||||
|
big.NewInt(0), |
||||||
|
big.NewInt(0), |
||||||
|
nil, |
||||||
|
}} |
||||||
|
return newStake, nil |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
// ErrInvalidSig is a bad signature
|
||||||
|
ErrInvalidSig = errors.New("invalid transaction v, r, s values") |
||||||
|
) |
||||||
|
|
||||||
|
// StakingTransactions is a stake slice type for basic sorting.
|
||||||
|
type StakingTransactions []*StakingTransaction |
||||||
|
|
||||||
|
// Hash hashes the RLP encoding of tx.
|
||||||
|
// It uniquely identifies the transaction.
|
||||||
|
func (tx *StakingTransaction) Hash() common.Hash { |
||||||
|
if hash := tx.hash.Load(); hash != nil { |
||||||
|
return hash.(common.Hash) |
||||||
|
} |
||||||
|
v := hash.FromRLP(tx) |
||||||
|
tx.hash.Store(v) |
||||||
|
return v |
||||||
|
} |
||||||
|
|
||||||
|
// WithSignature returns a new transaction with the given signature.
|
||||||
|
func (tx *StakingTransaction) WithSignature(signer Signer, sig []byte) (*StakingTransaction, error) { |
||||||
|
r, s, v, err := signer.SignatureValues(tx, sig) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
cpy := &StakingTransaction{data: tx.data} |
||||||
|
cpy.data.R, cpy.data.S, cpy.data.V = r, s, v |
||||||
|
return cpy, nil |
||||||
|
} |
||||||
|
|
||||||
|
// ChainID is what chain this staking transaction for
|
||||||
|
func (tx *StakingTransaction) ChainID() *big.Int { |
||||||
|
return deriveChainID(tx.data.V) |
||||||
|
} |
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder
|
||||||
|
func (tx *StakingTransaction) EncodeRLP(w io.Writer) error { |
||||||
|
return rlp.Encode(w, &tx.data) |
||||||
|
} |
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder
|
||||||
|
func (tx *StakingTransaction) DecodeRLP(s *rlp.Stream) error { |
||||||
|
_, size, _ := s.Kind() |
||||||
|
err := s.Decode(&tx.data) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
if err == nil { |
||||||
|
tx.size.Store(common.StorageSize(rlp.ListSize(size))) |
||||||
|
} |
||||||
|
return err |
||||||
|
} |
Loading…
Reference in new issue