func TestSendTxSignable(t *testing.T) { sendTx := &SendTx{ Inputs: []*TxInput{ &TxInput{ Address: []byte("input1"), Amount: 12345, Sequence: 67890, }, &TxInput{ Address: []byte("input2"), Amount: 111, Sequence: 222, }, }, Outputs: []*TxOutput{ &TxOutput{ Address: []byte("output1"), Amount: 333, }, &TxOutput{ Address: []byte("output2"), Amount: 444, }, }, } signBytes := acm.SignBytes(chainID, sendTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr) } }
func (data *Data) Hash() []byte { if data.hash == nil { bs := make([]interface{}, len(data.Txs)) for i, tx := range data.Txs { bs[i] = acm.SignBytes(config.GetString("chain_id"), tx) } data.hash = merkle.SimpleHashFromBinaries(bs) // NOTE: leaves are TxIDs. } return data.hash }
func TestRebondTxSignable(t *testing.T) { rebondTx := &RebondTx{ Address: []byte("address1"), Height: 111, } signBytes := acm.SignBytes(chainID, rebondTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[19,{"address":"6164647265737331","height":111}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for RebondTx") } }
// Verify that +2/3 of the set had signed the given signBytes func (valSet *ValidatorSet) VerifyValidation(chainID string, hash []byte, parts PartSetHeader, height int, v *Validation) error { if valSet.Size() != len(v.Precommits) { return fmt.Errorf("Invalid validation -- wrong set size: %v vs %v", valSet.Size(), len(v.Precommits)) } if height != v.Height() { return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, v.Height()) } talliedVotingPower := int64(0) round := v.Round() for idx, precommit := range v.Precommits { // may be nil if validator skipped. if precommit == nil { continue } if precommit.Height != height { return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, precommit.Height) } if precommit.Round != round { return fmt.Errorf("Invalid validation -- wrong round: %v vs %v", round, precommit.Round) } if precommit.Type != VoteTypePrecommit { return fmt.Errorf("Invalid validation -- not precommit @ index %v", idx) } _, val := valSet.GetByIndex(idx) // Validate signature precommitSignBytes := account.SignBytes(chainID, precommit) if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) { return fmt.Errorf("Invalid validation -- invalid signature: %v", precommit) } if !bytes.Equal(precommit.BlockHash, hash) { continue // Not an error, but doesn't count } if !parts.Equals(precommit.BlockPartsHeader) { continue // Not an error, but doesn't count } // Good precommit! talliedVotingPower += val.VotingPower } if talliedVotingPower > valSet.TotalVotingPower()*2/3 { return nil } else { return fmt.Errorf("Invalid validation -- insufficient voting power: got %v, needed %v", talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1)) } }
func TestProposalSignable(t *testing.T) { proposal := &Proposal{ Height: 12345, Round: 23456, BlockPartsHeader: types.PartSetHeader{111, []byte("blockparts")}, POLRound: -1, } signBytes := acm.SignBytes(config.GetString("chain_id"), proposal) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_round":-1,"round":23456}}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr) } }
func (voteSet *VoteSet) addVote(val *Validator, valIndex int, vote *Vote) (bool, int, error) { // Make sure the step matches. (or that vote is commit && round < voteSet.round) if (vote.Height != voteSet.height) || (vote.Round != voteSet.round) || (vote.Type != voteSet.type_) { return false, 0, ErrVoteUnexpectedStep } // Check signature. if !val.PubKey.VerifyBytes(acm.SignBytes(config.GetString("chain_id"), vote), vote.Signature) { // Bad signature. return false, 0, ErrVoteInvalidSignature } // If vote already exists, return false. if existingVote := voteSet.votes[valIndex]; existingVote != nil { if bytes.Equal(existingVote.BlockHash, vote.BlockHash) { return false, valIndex, nil } else { return false, valIndex, &ErrVoteConflictingSignature{ VoteA: existingVote, VoteB: vote, } } } // Add vote. voteSet.votes[valIndex] = vote voteSet.votesBitArray.SetIndex(valIndex, true) blockKey := string(vote.BlockHash) + string(wire.BinaryBytes(vote.BlockPartsHeader)) totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower voteSet.votesByBlock[blockKey] = totalBlockHashVotes voteSet.totalVotes += val.VotingPower // If we just nudged it up to two thirds majority, add it. if totalBlockHashVotes > voteSet.valSet.TotalVotingPower()*2/3 && (totalBlockHashVotes-val.VotingPower) <= voteSet.valSet.TotalVotingPower()*2/3 { voteSet.maj23Hash = vote.BlockHash voteSet.maj23PartsHeader = vote.BlockPartsHeader voteSet.maj23Exists = true } return true, valIndex, nil }
func (privVal *PrivValidator) SignRebondTx(chainID string, rebondTx *RebondTx) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() if privVal.LastHeight < rebondTx.Height { // Persist height/round/step // Prevent doing anything else for this rebondTx.Height. privVal.LastHeight = rebondTx.Height privVal.LastRound = math.MaxInt32 // MaxInt64 overflows on 32bit architectures. privVal.LastStep = math.MaxInt8 privVal.save() // Sign rebondTx.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, rebondTx)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height)) } }
func TestNameTxSignable(t *testing.T) { nameTx := &NameTx{ Input: &TxInput{ Address: []byte("input1"), Amount: 12345, Sequence: 250, }, Name: "google.com", Data: "secretly.not.google.com", Fee: 1000, } signBytes := acm.SignBytes(chainID, nameTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"696E70757431","amount":12345,"sequence":250},"name":"google.com"}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) } }
func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() if privVal.LastHeight < proposal.Height || privVal.LastHeight == proposal.Height && privVal.LastRound < proposal.Round || privVal.LastHeight == 0 && privVal.LastRound == 0 && privVal.LastStep == stepNone { // Persist height/round/step privVal.LastHeight = proposal.Height privVal.LastRound = proposal.Round privVal.LastStep = stepPropose privVal.save() // Sign proposal.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, proposal)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v", proposal.Height, proposal.Round)) } }
func TestCallTxSignable(t *testing.T) { callTx := &CallTx{ Input: &TxInput{ Address: []byte("input1"), Amount: 12345, Sequence: 67890, }, Address: []byte("contract1"), GasLimit: 111, Fee: 222, Data: []byte("data1"), } signBytes := acm.SignBytes(chainID, callTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) } }
func TestPermissionsTxSignable(t *testing.T) { permsTx := &PermissionsTx{ Input: &TxInput{ Address: []byte("input1"), Amount: 12345, Sequence: 250, }, PermArgs: &ptypes.SetBaseArgs{ Address: []byte("address1"), Permission: 1, Value: true, }, } signBytes := acm.SignBytes(chainID, permsTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[32,{"args":"[2,{"address":"6164647265737331","permission":1,"value":true}]","input":{"address":"696E70757431","amount":12345,"sequence":250}}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) } }
func TestBondTxSignable(t *testing.T) { privKeyBytes := make([]byte, 64) privAccount := acm.GenPrivAccountFromPrivKeyBytes(privKeyBytes) bondTx := &BondTx{ PubKey: privAccount.PubKey.(acm.PubKeyEd25519), Inputs: []*TxInput{ &TxInput{ Address: []byte("input1"), Amount: 12345, Sequence: 67890, }, &TxInput{ Address: []byte("input2"), Amount: 111, Sequence: 222, }, }, UnbondTo: []*TxOutput{ &TxOutput{ Address: []byte("output1"), Amount: 333, }, &TxOutput{ Address: []byte("output2"), Amount: 444, }, }, } signBytes := acm.SignBytes(chainID, bondTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, config.GetString("chain_id")) if signStr != expected { t.Errorf("Unexpected sign string for BondTx. \nGot %s\nExpected %s", signStr, expected) } }
// This should match the leaf hashes of Block.Data.Hash()'s SimpleMerkleTree. func TxID(chainID string, tx Tx) []byte { signBytes := acm.SignBytes(chainID, tx) return wire.BinaryRipemd160(signBytes) }
func (privVal *PrivValidator) SignVoteUnsafe(chainID string, vote *Vote) { vote.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, vote)).(acm.SignatureEd25519) }