1.遍历交易集合txs获取全部的消费记录inputMap 2.从区块链获取inputMap的消费记录input对应的output 3.传入output的集合,逐笔验证签名
验证: 1.复制一份新的交易对象(input的签名和公钥置空) 2.对复制的交易进行hash,获取签名需要的hash ( 获取input的output所在的交易 设置vin的公钥为utxo的pubhash 对交易进行hash ) 3.验证签名
type Client struct {
Blockchain *blockchain.Blockchain
}
type Blockchain struct {
Tip []byte
DB *bolt.DB
}
type UTXO struct {
Hash []byte
Index int
Output *TXOutput
}
type TXOutput struct {
Value int
PubHash []byte
}
type TXInput struct {
TxHash []byte
Vout int
ScriptSig []byte
PubKey []byte
}
func (client *Client)verifyTxs(txs []*transaction.Transaction) (validTxs []*transaction.Transaction,msg string, err error) {
client.getBlockchainAndSetToClient()
iterator := client.Blockchain.Iterator()
var inputMap = make(map[string]*transaction.TXInput)
for _, tx := range txs {
for _, vin := range tx.Vins {
inputMap[string(vin.TxHash)] = vin
}
}
var utxos []*transaction.UTXO
utxos,msg,err = getUTXOsByInputMap(iterator,inputMap)
for _, tx := range txs {
isValid,_ := tx.VerifySign(utxos)
if !isValid {
continue
}
validTxs = append(validTxs, tx)
}
return
}
func (blc *Blockchain) Iterator() *BlockchainIterator {
if blc.DB == nil {
return nil
}
return &BlockchainIterator{NextHash: blc.Tip, DB: blc.DB}
}
验证交易的签名
func (tx *Transaction) VerifySign(utxos []*UTXO) (isValid bool,msg string) {
copyTx := tx.trimmedCopy()
curve := elliptic.P256()
for _, vin := range tx.Vins {
var signHash []byte
signHash,msg = copyTx.getHashForSignOrVerify(utxos,*vin)
if msg != "" {
log.Println(msg)
return
}
r := big.Int{}
s := big.Int{}
sigLen := len(vin.ScriptSig)
r.SetBytes(vin.ScriptSig[:(sigLen/2)])
s.SetBytes(vin.ScriptSig[(sigLen/2):])
x := big.Int{}
y := big.Int{}
keyLen := len(vin.PubKey)
x.SetBytes(vin.PubKey[:(keyLen/2)])
y.SetBytes(vin.PubKey[(keyLen/2):])
pubKey := ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}
isValid = ecdsa.Verify(&pubKey,signHash,&r,&s)
if !isValid {
msg = "签名验证失败"
log.Println(msg)
return
}
}
return
}
func (tx *Transaction)getHashForSignOrVerify(utxos []*UTXO,vin TXInput) (hashByte []byte, msg string) {
var utxo *UTXO
for _, u := range utxos {
if bytes.Compare(u.Hash,vin.TxHash) == 0 && u.Index == vin.Vout {
utxo = u
break
}
}
if utxo == nil {
msg = "交易错误,根据input的信息未能找到对应的utxo"
log.Println(msg,vin.TxHash)
return
}
vin.ScriptSig = nil
vin.PubKey = utxo.Output.PubHash
hashByte = tx.txHashForSignHash()
if hashByte == nil {
msg = "获取签名需要的hash失败"
log.Println(msg)
return
}
return
}
func (tx *Transaction) txHashForSignHash() []byte {
copyTx := *tx
copyTx.TxHash = []byte{}
err := copyTx.hashTransaction()
if err != nil {
return nil
}
return copyTx.TxHash
}
func (tx *Transaction) hashTransaction() (err error) {
var result bytes.Buffer
encoder := gob.NewEncoder(&result)
err = encoder.Encode(tx)
if err != nil {
log.Println(err)
return err
}
txHash := sha256.Sum256(result.Bytes())
tx.TxHash = txHash[:]
return nil
}
func (tx *Transaction) trimmedCopy() Transaction {
var inputs []*TXInput
var outputs []*TXOutput
for _, vin := range tx.Vins {
inputs = append(inputs, &TXInput{TxHash: vin.TxHash,Vout: vin.Vout,ScriptSig: nil,PubKey: nil} )
}
for _, vout := range tx.Vouts {
outputs = append(outputs, &TXOutput{Value: vout.Value,PubHash: vout.PubHash})
}
return Transaction{TxHash: tx.TxHash,Vins: inputs,Vouts: outputs}
}
根据inputMap获取全部utxos
func getUTXOsByInputMap(iterator *BlockchainIterator,inputMap map[string]*transaction.TXInput) (utxos []*transaction.UTXO,msg string, err error) {
for {
if len(inputMap) == 0 {
return
}
var b *block.Block
b,msg,err = iterator.Next()
if msg != "" || err != nil {
log.Println(msg,err)
return
}
for _, tx := range b.Txs {
input := inputMap[string(tx.TxHash)]
if input == nil {
continue
}
if input.Vout > len(tx.Vouts) {
continue
}
if bytes.Compare(wallet.Ripemd160Hash(input.TxHash),tx.Vouts[input.Vout].PubHash) == 0 {
continue
}
utxos = append(utxos, &transaction.UTXO{Hash: tx.TxHash,Index: input.Vout,Output: tx.Vouts[input.Vout]})
delete(inputMap,string(tx.TxHash))
}
}
}
func (iterator *BlockchainIterator) Next() (block *block.Block,msg string, err error) {
err = iterator.DB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("blocks"))
if b == nil {
log.Println(err)
return errors.New(BlockTableName + " is nil")
}
block,msg,err = GetBlockFromDB(b,iterator.NextHash)
if err != nil {
log.Println(err)
return err
}
if block == nil {
return nil
}
iterator.NextHash = block.PrevBlockHash
return err
})
return
}
func GetBlockFromDB(b *bolt.Bucket,key []byte) (blockStruct *block.Block, msg string,err error) {
blockBytes := b.Get(key)
if blockBytes == nil {
msg = "DB:"+string(key)+"没有对应的block"
log.Println(msg)
return
}
blockStruct,err = DeserializeBlock(blockBytes)
if err != nil {
log.Println(err)
}
return
}
func DeserializeBlock(blockBytes []byte) (*Block,error) {
var b Block
decoder := gob.NewDecoder(bytes.NewReader(blockBytes))
err := decoder.Decode(&b)
return &b,err
}
获取区块链对象
func (client *Client) getBlockchainAndSetToClient() {
blc = &Blockchain{}
var db *bolt.DB
db,err = bolt.Open("blockchain.db",0600,&bolt.Options{Timeout: 1 * time.Second})
if err != nil {
log.Println(err)
return
}
blc.DB = db
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("blocks"))
if b == nil {
log.Println("blocks is nil")
return
}
blc.Tip = b.Get([]byte("l"))
return nil
})
client.Blockchain = blc
}
|