func (inv *Inventory) handleTransaction(tx *messages.Transaction) { if !tx.MatchesFilter(inv.filter.Filter()) { log.Printf("Received transaction %x not matching the filter.", tx.Hash()) } else { log.Printf("Received transaction %x matching the filter: %x", tx.Hash(), tx.Data()) } inv.addTxData(tx.Hash(), tx) w := inv.config.Wallet if w != nil { if w.HasNewAddressesToWatch() { // A wallet has had its address space expand and we // need to add these new addresses to the filter and // unless we're certain this is a fresh transaction (as // opposed to a historic one), we need to rescan // history. for _, o := range w.WatchObjects() { inv.filter.Watch(o, filterMayNeedUpdate) } // TODO Decide whether or not to rescan history. This // can be done easily (but slowely) by setting height // back to 0. } } }
func (inv *Inventory) VerifyTransaction(tx *messages.Transaction) (bool, error) { var inputValue, outputValue uint64 for index, input := range tx.Inputs { stack := script.Stack{} err := stack.Execute(input.Signature, nil) if err != nil { return false, fmt.Errorf("Failed to push signature: %v", err) } prev := input.PreviousOutput d, found := inv.txHashes[string(prev.Hash)] if !found { return false, fmt.Errorf("Input tx %x not found in map.", prev.Hash) } inputTx := d.tx output := inputTx.Outputs[prev.Index] inputValue += output.Value data := &script.Data{ Hasher: func(c uint32) []byte { return utils.DoubleHash(tx.SignSerialize( index, output.Script, c)) }} err = stack.Execute(output.Script, data) if err != nil { return false, fmt.Errorf("Failed to execute script: %v", err) } if !stack.CheckSuccess() { return false, fmt.Errorf("Signature on input %d not valid.", index) } } for _, output := range tx.Outputs { outputValue += output.Value } if outputValue > inputValue { return false, fmt.Errorf("Outputs have higher value (%d) than inputs (%d).", outputValue, inputValue) } return true, nil }
func (inv *Inventory) addTxData(hash []byte, data *messages.Transaction) { version, found := inv.txHashes[string(hash)] if !found { id := data.Fingerprint() log.Printf("Adding transaction hash %x for transaction %x", hash, id) version = &TxVersion{Hash: hash, tx: data} inv.txHashes[string(hash)] = version inv.config.Database.StoreNewTransaction(version) } else if version.tx == nil { version.tx = data inv.config.Database.StoreNewTransaction(version) if version.Block != nil { // This tx was confirmed earlier, but couldn't // invalidate duplicates until now; confirm it again. inv.transactionVersionConfirmed(version) } } tx, found := inv.transactions[string(version.Id())] if !found { log.Printf("Adding hash %x to transaction %x", hash, version.Id()) tx = &Transaction{ id: version.Id(), timestamp: time.Now(), versions: make(map[string]*messages.Transaction), block: version.Block, } inv.transactions[string(version.Id())] = tx } else if tx.block != nil { // Another version of this transaction has already been confirmed. return } tx.versions[string(hash)] = data inv.UpdateTxOutputs(version) // Add transaction to filter. Remote nodes will do the same, so there's // no need to update them. inv.filter.Watch(hash, filterNoUpdateNeeded) // TODO verify TX }