Skip to content

Commit

Permalink
Account-based chain phase 2: add ULT test for Vote
Browse files Browse the repository at this point in the history
  • Loading branch information
dustinxie committed Jun 5, 2018
1 parent 456d382 commit e380921
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 6 deletions.
4 changes: 2 additions & 2 deletions blockchain/action/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ func (tsf *Transfer) Hash() common.Hash32B {
return blake2b.Sum256(hash[:])
}

// Sign signs the Transfer using sender's private key
func Sign(raw []byte, sender *iotxaddress.Address) ([]byte, error) {
// SignTransfer signs the Transfer using sender's private key
func SignTransfer(raw []byte, sender *iotxaddress.Address) ([]byte, error) {
tsf := &Transfer{}
if err := tsf.Deserialize(raw); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal Transfer")
Expand Down
2 changes: 1 addition & 1 deletion blockchain/action/transfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestTransfer(t *testing.T) {
raw, err := tsf.Serialize()
assert.Nil(err)
// Sign the transfer
signed, err := Sign(raw, sender)
signed, err := SignTransfer(raw, sender)
assert.Nil(err)
// deserialize
tsf2 := &Transfer{}
Expand Down
66 changes: 63 additions & 3 deletions blockchain/action/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ package action

import (
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
"golang.org/x/crypto/blake2b"

"bytes"
"github.com/iotexproject/iotex-core/common"
cp "github.com/iotexproject/iotex-core/crypto"
"github.com/iotexproject/iotex-core/iotxaddress"
"github.com/iotexproject/iotex-core/proto"
)

Expand All @@ -28,6 +32,16 @@ type (
}
)

// NewVote returns a Vote instance
func NewVote(timestamp uint64, selfPubKey []byte, votePubKey []byte) *Vote {
pbVote := &iproto.VotePb{
Timestamp: timestamp,
SelfPubkey: selfPubKey,
VotePubkey: votePubKey,
}
return &Vote{pbVote}
}

// TotalSize returns the total size of this Vote
func (v *Vote) TotalSize() uint32 {
size := TimestampSizeInBytes
Expand All @@ -43,7 +57,7 @@ func (v *Vote) ByteStream() []byte {
common.MachineEndian.PutUint64(stream, v.Timestamp)
stream = append(stream, v.SelfPubkey...)
stream = append(stream, v.VotePubkey...)
stream = append(stream, v.Signature...)
// Signature = Sign(hash(ByteStream())), so not included
return stream
}

Expand All @@ -54,7 +68,7 @@ func (v *Vote) ConvertToVotePb() *iproto.VotePb {

// Serialize returns a serialized byte stream for the Transfer
func (v *Vote) Serialize() ([]byte, error) {
return proto.Marshal(v)
return proto.Marshal(v.ConvertToVotePb())
}

// ConvertFromVotePb converts Vote to protobuf's VotePb
Expand All @@ -64,9 +78,11 @@ func (v *Vote) ConvertFromVotePb(pbVote *iproto.VotePb) {

// Deserialize parse the byte stream into Vote
func (v *Vote) Deserialize(buf []byte) error {
if err := proto.Unmarshal(buf, v); err != nil {
pbVote := &iproto.VotePb{}
if err := proto.Unmarshal(buf, pbVote); err != nil {
return err
}
v.ConvertFromVotePb(pbVote)
return nil
}

Expand All @@ -75,3 +91,47 @@ func (v *Vote) Hash() common.Hash32B {
hash := blake2b.Sum256(v.ByteStream())
return blake2b.Sum256(hash[:])
}

// SignVote signs the Vote using sender's private key
func SignVote(raw []byte, sender *iotxaddress.Address) ([]byte, error) {
vote := &Vote{}
if err := vote.Deserialize(raw); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal Vote")
}
// check the sender is correct
if bytes.Compare(vote.SelfPubkey, sender.PublicKey) != 0 {
return nil, errors.Wrapf(ErrActionError, "signing pubKey %x does not match with Vote pubKey %x",
vote.SelfPubkey, sender.PublicKey)
}
// check the public key is actually owned by sender
pkhash := iotxaddress.GetPubkeyHash(sender.RawAddress)
if bytes.Compare(pkhash, iotxaddress.HashPubKey(sender.PublicKey)) != 0 {
return nil, errors.Wrapf(ErrActionError, "signing addr %s does not own correct public key",
sender.RawAddress)
}
if err := vote.sign(sender); err != nil {
return nil, err
}
return vote.Serialize()
}

// Verify verifies the Vote using sender's public key
func (v *Vote) Verify(sender *iotxaddress.Address) error {
hash := v.Hash()
if success := cp.Verify(sender.PublicKey, hash[:], v.Signature); success {
return nil
}
return errors.Wrapf(ErrActionError, "Failed to verify Vote signature = %x", v.Signature)
}

//======================================
// private functions
//======================================

func (v *Vote) sign(sender *iotxaddress.Address) error {
hash := v.Hash()
if v.Signature = cp.Sign(sender.PrivateKey, hash[:]); v.Signature != nil {
return nil
}
return errors.Wrapf(ErrActionError, "Failed to sign Vote hash = %x", hash)
}
38 changes: 38 additions & 0 deletions blockchain/action/vote_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2018 IoTeX
// This is an alpha (internal) release and is not suitable for production. This source code is provided ‘as is’ and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package action

import (
"testing"

"github.com/iotexproject/iotex-core/iotxaddress"
"github.com/stretchr/testify/assert"
)

func TestVote(t *testing.T) {
assert := assert.New(t)
sender, err := iotxaddress.NewAddress(true, chainid)
assert.Nil(err)
recipient, err := iotxaddress.NewAddress(true, chainid)
assert.Nil(err)
// Create new vote and put on wire
vote := NewVote(0, sender.PublicKey, recipient.PublicKey)
raw, err := vote.Serialize()
assert.Nil(err)
// Sign the transfer
signed, err := SignVote(raw, sender)
assert.Nil(err)
// deserialize
vote2 := &Vote{}
assert.Nil(vote2.Deserialize(signed))
// test data match before/after serialization
assert.Equal(vote.Hash(), vote2.Hash())
// test signature
assert.Nil(vote2.Verify(sender))
assert.NotNil(vote2.Verify(recipient))
assert.NotNil(vote.Verify(sender))
}

0 comments on commit e380921

Please sign in to comment.