示例#1
0
func NewReadableTransaction(t *coin.Transaction) ReadableTransaction {

	sigs := make([]string, len(t.Sigs))
	for i, _ := range t.Sigs {
		sigs[i] = t.Sigs[i].Hex()
	}

	in := make([]string, len(t.In))
	for i, _ := range t.In {
		in[i] = t.In[i].Hex()
	}
	out := make([]ReadableTransactionOutput, len(t.Out))
	for i, _ := range t.Out {
		out[i] = NewReadableTransactionOutput(&t.Out[i])
	}
	return ReadableTransaction{
		Length:    t.Length,
		Type:      t.Type,
		Hash:      t.Hash().Hex(),
		InnerHash: t.InnerHash.Hex(),

		Sigs: sigs,
		In:   in,
		Out:  out,
	}
}
示例#2
0
// Adds a coin.Transaction to the pool, or updates an existing one's timestamps
// Returns an error if txn is invalid, and whether the transaction already
// existed in the pool.
func (self *UnconfirmedTxnPool) RecordTxn(bc *coin.Blockchain,
	t coin.Transaction, addrs map[coin.Address]byte, maxSize int,
	burnFactor uint64) (error, bool) {
	if err := VerifyTransaction(bc, &t, maxSize, burnFactor); err != nil {
		return err, false
	}
	if err := bc.VerifyTransaction(t); err != nil {
		return err, false
	}

	// Update if we already have this txn
	ut, ok := self.Txns[t.Hash()]
	if ok {
		now := util.Now()
		ut.Received = now
		ut.Checked = now
		self.Txns[ut.Txn.Hash()] = ut
		return nil, true
	}

	// Add txn to index
	self.Txns[t.Hash()] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs)
	// Add predicted unspents
	uxs := coin.CreateExpectedUnspents(t)
	for i, _ := range uxs {
		self.Unspent.Add(uxs[i])
	}

	return nil, false
}
示例#3
0
// Adds a coin.Transaction to the pool, or updates an existing one's timestamps
// Returns an error if txn is invalid, and whether the transaction already
// existed in the pool.
func (self *UnconfirmedTxnPool) RecordTxn(bc *coin.Blockchain,
	t coin.Transaction, addrs map[cipher.Address]byte, maxSize int,
	burnFactor uint64) (error, bool) {
	if err := VerifyTransaction(bc, &t, maxSize, burnFactor); err != nil {
		return err, false
	}
	if err := bc.VerifyTransaction(t); err != nil {
		return err, false
	}

	// Update if we already have this txn
	h := t.Hash()
	ut, ok := self.Txns[h]
	if ok {
		now := util.Now()
		ut.Received = now
		ut.Checked = now
		self.Txns[h] = ut
		return nil, true
	}

	// Add txn to index
	self.Txns[h] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs)
	// Add predicted unspents
	self.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t)

	return nil, false
}
示例#4
0
// InjectTxn adds a coin.Transaction to the pool, or updates an existing one's timestamps
// Returns an error if txn is invalid, and whether the transaction already
// existed in the pool.
func (utp *UnconfirmedTxnPool) InjectTxn(bc *Blockchain,
	t coin.Transaction) (error, bool) {

	if err := t.Verify(); err != nil {
		return err, false
	}

	if err := VerifyTransactionFee(bc, &t); err != nil {
		return err, false
	}
	if err := bc.VerifyTransaction(t); err != nil {
		return err, false
	}

	// Update if we already have this txn
	h := t.Hash()
	ut, ok := utp.Txns[h]
	if ok {
		now := util.Now()
		ut.Received = now
		ut.Checked = now
		utp.Txns[h] = ut
		return nil, true
	}

	// Add txn to index
	unspent := bc.GetUnspent()
	utp.Txns[h] = utp.createUnconfirmedTxn(unspent, t)
	// Add predicted unspents
	utp.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t)

	return nil, false
}
示例#5
0
func (fg fakeGateway) InjectTransaction(txn coin.Transaction) (coin.Transaction, error) {
	if _, v := fg.injectRawTxMap[txn.Hash().Hex()]; v {
		return txn, nil
	}

	return txn, errors.New("inject transaction failed")
}
示例#6
0
func assertValidUnconfirmed(t *testing.T, txns map[cipher.SHA256]UnconfirmedTxn,
	txn coin.Transaction) {
	ut, ok := txns[txn.Hash()]
	assert.True(t, ok)
	assert.Equal(t, ut.Txn, txn)
	assert.True(t, ut.Announced.IsZero())
	assert.False(t, ut.Received.IsZero())
	assert.False(t, ut.Checked.IsZero())
}
func assertValidUnconfirmed(t *testing.T, txns map[coin.SHA256]UnconfirmedTxn,
	txn coin.Transaction, didAnnounce, isOurReceive, isOurSpend bool) {
	ut, ok := txns[txn.Hash()]
	assert.True(t, ok)
	assert.Equal(t, ut.Txn, txn)
	assert.Equal(t, ut.IsOurReceive, isOurReceive)
	assert.Equal(t, ut.IsOurSpend, isOurSpend)
	assert.Equal(t, ut.Announced.IsZero(), !didAnnounce)
	assert.False(t, ut.Received.IsZero())
	assert.False(t, ut.Checked.IsZero())
}
示例#8
0
func assertValidUnspents(t *testing.T, bh coin.BlockHeader, tx coin.Transaction,
	uxo coin.UxArray) {
	assert.Equal(t, len(tx.Out), len(uxo))
	for i, ux := range uxo {
		assert.Equal(t, bh.Time, ux.Head.Time)
		assert.Equal(t, bh.BkSeq, ux.Head.BkSeq)
		assert.Equal(t, tx.Hash(), ux.Body.SrcTransaction)
		assert.Equal(t, tx.Out[i].Address, ux.Body.Address)
		assert.Equal(t, tx.Out[i].Coins, ux.Body.Coins)
		assert.Equal(t, tx.Out[i].Hours, ux.Body.Hours)
	}
}
示例#9
0
// Adds a coin.Transaction to the pool
//func (self *UnconfirmedTxnPool) InjectTxn(bc *coin.Blockchain,
//    t coin.Transaction, addrs map[cipher.Address]byte, didAnnounce bool) error {
func (self *UnconfirmedTxnPool) InjectTxn(t coin.Transaction) error {

	now := time.Now().Unix()
	//announcedAt := util.ZeroTime()

	ut := UnconfirmedTxn{
		Txn:       t,
		Received:  now,
		Checked:   now,
		Announced: 0, //set to 0 until announced
	}
	self.Txns[t.Hash()] = ut
	return nil
}
示例#10
0
func assertValidUnspent(t *testing.T, bc *coin.Blockchain,
	unspent TxnUnspents, tx coin.Transaction) {
	expect := coin.CreateUnspents(bc.Head().Head, tx)
	assert.NotEqual(t, len(expect), 0)
	sum := 0
	for _, uxs := range unspent {
		sum += len(uxs)
	}
	assert.Equal(t, len(expect), sum)
	uxs := unspent[tx.Hash()]
	for _, ux := range expect {
		found := false
		for _, u := range uxs {
			if u.Hash() == ux.Hash() {
				found = true
				break
			}
		}
		assert.True(t, found)
	}
}
示例#11
0
func TransactionToJSON(tx coin.Transaction) string {

	var o TransactionJSON

	if err := tx.Verify(); err != nil {
		log.Panic("Input Transaction Invalid: Cannot serialize to JSON, fails verify")
	}

	o.Hash = tx.Hash().Hex()
	o.InnerHash = tx.InnerHash.Hex()

	if tx.InnerHash != tx.HashInner() {
		log.Panic("TransactionToJSON called with invalid transaction, inner hash mising")
	}

	o.Sigs = make([]string, len(tx.Sigs))
	o.In = make([]string, len(tx.In))
	o.Out = make([]TransactionOutputJSON, len(tx.Out))

	for i, sig := range tx.Sigs {
		o.Sigs[i] = sig.Hex()
	}
	for i, x := range tx.In {
		o.In[i] = x.Hex() //hash to hex
	}
	for i, y := range tx.Out {
		o.Out[i] = NewTransactionOutputJSON(y, tx.InnerHash)
	}

	b, err := json.MarshalIndent(o, "", "  ")
	if err != nil {
		log.Panic("Cannot serialize transaction as JSON")
	}

	return string(b)
}
示例#12
0
func TransactionFromJSON(str string) (coin.Transaction, error) {

	var TxIn TransactionJSON
	err := json.Unmarshal([]byte(str), TxIn)

	if err != nil {
		errors.New("cannot deserialize")
	}

	var tx coin.Transaction

	tx.Sigs = make([]cipher.Sig, len(TxIn.Sigs))
	tx.In = make([]cipher.SHA256, len(TxIn.In))
	tx.Out = make([]coin.TransactionOutput, len(TxIn.Out))

	for i, _ := range tx.Sigs {
		sig2, err := cipher.SigFromHex(TxIn.Sigs[i])
		if err != nil {
			return coin.Transaction{}, errors.New("invalid signature")
		}
		tx.Sigs[i] = sig2
	}

	for i, _ := range tx.In {
		hash, err := cipher.SHA256FromHex(TxIn.In[i])
		if err != nil {
			return coin.Transaction{}, errors.New("invalid signature")
		}
		tx.In[i] = hash
	}

	for i, _ := range tx.Out {
		out, err := TransactionOutputFromJSON(TxIn.Out[i])
		if err != nil {
			return coin.Transaction{}, errors.New("invalid output")
		}
		tx.Out[i] = out
	}

	tx.Length = uint32(tx.Size())
	tx.Type = 0

	hash, err := cipher.SHA256FromHex(TxIn.Hash)
	if err != nil {
		return coin.Transaction{}, errors.New("invalid hash")
	}
	if hash != tx.Hash() {

	}

	InnerHash, err := cipher.SHA256FromHex(TxIn.Hash)

	if InnerHash != tx.InnerHash {
		return coin.Transaction{}, errors.New("inner hash")
	}

	err = tx.Verify()
	if err != nil {
		return coin.Transaction{}, errors.New("transaction failed verification")
	}

	return tx, nil
}
示例#13
0
func TestProcessTransactions(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	fmt.Println("genesis time:", bc.GetGenesisBlock().Time())
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Invalid, no transactions in block
	// arbitrating=false
	txns, err := bc.processTransactions(coin.Transactions{}, false)
	assert.Nil(t, txns)
	assertError(t, err, "No transactions")
	// arbitrating=true
	txns, err = bc.processTransactions(coin.Transactions{}, true)
	assert.Equal(t, len(txns), 0)
	assert.Nil(t, err)

	// Invalid, txn.Verify() fails
	// TODO -- combine all txn.Verify() failures into one test
	// method, and call it from here, from ExecuteBlock(), from
	// Verify(), from VerifyTransaction()
	txns = coin.Transactions{}
	txn := coin.Transaction{}
	txn.PushInput(ux.Hash())
	txn.PushOutput(genAddress, 777, 100)
	txn.SignInputs([]cipher.SecKey{genSecret})
	txn.UpdateHeader()
	txns = append(txns, txn)
	// arbitrating=false
	txns2, err := bc.processTransactions(txns, false)
	assert.Nil(t, txns2)
	assertError(t, err,
		"Transaction outputs must be multiple of 1e6 base units")
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.NotNil(t, txns2)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 0)

	// Invalid, duplicate unspent will be created by these txns
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txns = coin.Transactions{txn, txn}
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "Duplicate unspent output across transactions")
	assert.Nil(t, txns2)
	// arbitrating=true.  One of the offending transactions should be removed
	txns2, err = bc.processTransactions(txns, true)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 1)
	assert.Equal(t, txns2[0], txn)

	// Check that a new output will not collide with the existing pool
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txns = coin.Transactions{txn}
	uxb := coin.UxBody{
		SrcTransaction: txn.Hash(),
		Coins:          txn.Out[0].Coins,
		Hours:          txn.Out[0].Hours,
		Address:        txn.Out[0].Address,
	}
	bc.GetUnspent().Add(coin.UxOut{Body: uxb})
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "New unspent collides with existing unspent")
	assert.Nil(t, txns2)
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.Equal(t, len(txns2), 0)
	assert.NotNil(t, txns2)
	assert.Nil(t, err)

	// Spending of duplicate inputs being spent across txns
	txn, _ = makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txn2, _ := makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 100,
		100)
	txn2.Out = nil
	txn2.PushOutput(makeAddress(), 1e6, 100)
	txn2.PushOutput(makeAddress(), ux.Body.Coins-1e6, 100)
	txn2.Sigs = nil
	txn2.SignInputs([]cipher.SecKey{genSecret})
	txn2.UpdateHeader()
	txns = coin.SortTransactions(coin.Transactions{txn, txn2}, bc.TransactionFee)
	// arbitrating=false
	txns2, err = bc.processTransactions(txns, false)
	assertError(t, err, "Cannot spend output twice in the same block")
	assert.Nil(t, txns2)
	// arbitrating=true
	txns2, err = bc.processTransactions(txns, true)
	assert.Nil(t, err)
	assert.Equal(t, len(txns2), 1)
	assert.Equal(t, txns2[0], txns[0])
}
示例#14
0
func TestExecuteBlock(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	assert.Equal(t, bc.Len(), uint64(1))
	_, ux := addBlockToBlockchain(t, bc)
	assert.Equal(t, bc.Len(), uint64(3))

	// Invalid block returns error
	b := coin.Block{}
	uxs, err := bc.ExecuteBlock(&b)
	assert.NotNil(t, err)
	assert.Nil(t, uxs)

	// Valid block, spends are removed from the unspent pool, new ones are
	// added.  Blocks is updated, and new unspents are returns
	assert.Equal(t, bc.Len(), uint64(3))
	assert.Equal(t, len(bc.GetUnspent().Pool), 2)
	spuxs := splitUnspent(t, bc, ux)
	tx := coin.Transaction{}
	tx.PushInput(spuxs[0].Hash())
	coins := spuxs[0].Body.Coins
	extra := coins % 4e6
	coins = (coins - extra) / 4
	tx.PushOutput(genAddress, coins+extra, spuxs[0].Body.Hours/5)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/6)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/7)
	tx.PushOutput(genAddress, coins, spuxs[0].Body.Hours/8)
	tx.SignInputs([]cipher.SecKey{genSecret})
	tx.UpdateHeader()
	tx2 := coin.Transaction{}
	tx2.PushInput(spuxs[1].Hash())
	tx2.PushOutput(genAddress, spuxs[1].Body.Coins, spuxs[1].Body.Hours/10)
	tx2.SignInputs([]cipher.SecKey{genSecret})
	tx2.UpdateHeader()
	txns := coin.Transactions{tx, tx2}
	sTxns := coin.NewSortableTransactions(txns, bc.TransactionFee)
	unswapped := sTxns.IsSorted()
	txns = coin.SortTransactions(txns, bc.TransactionFee)
	assert.Nil(t, bc.verifyTransactions(txns))
	seq := bc.Head().Head.BkSeq
	b, err = bc.NewBlockFromTransactions(txns, bc.Time()+_incTime)
	assert.Equal(t, b.Head.BkSeq, seq+1)
	assert.Nil(t, err)
	assert.Equal(t, len(b.Body.Transactions), 2)
	assert.Equal(t, b.Body.Transactions, txns)
	uxs, err = bc.ExecuteBlock(&b)
	assert.Nil(t, err)
	assert.Equal(t, len(uxs), 5)
	// Check that all unspents look correct and are in the unspent pool
	txOuts := []coin.TransactionOutput{}
	if unswapped {
		txOuts = append(txOuts, tx.Out...)
		txOuts = append(txOuts, tx2.Out...)
	} else {
		txOuts = append(txOuts, tx2.Out...)
		txOuts = append(txOuts, tx.Out...)
	}
	for i, ux := range uxs {
		if unswapped {
			if i < len(tx.Out) {
				assert.Equal(t, ux.Body.SrcTransaction, tx.Hash())
			} else {
				assert.Equal(t, ux.Body.SrcTransaction, tx2.Hash())
			}
		} else {
			if i < len(tx2.Out) {
				assert.Equal(t, ux.Body.SrcTransaction, tx2.Hash())
			} else {
				assert.Equal(t, ux.Body.SrcTransaction, tx.Hash())
			}
		}
		assert.Equal(t, ux.Body.Address, txOuts[i].Address)
		assert.Equal(t, ux.Body.Coins, txOuts[i].Coins)
		assert.Equal(t, ux.Body.Hours, txOuts[i].Hours)
		assert.Equal(t, ux.Head.BkSeq, b.Head.BkSeq)
		assert.Equal(t, ux.Head.Time, b.Head.Time)
		assert.True(t, bc.GetUnspent().Has(ux.Hash()))
	}
	// Check that all spends are no longer in the pool
	txIns := []cipher.SHA256{}
	txIns = append(txIns, tx.In...)
	txIns = append(txIns, tx2.In...)
	for _, ux := range txIns {
		assert.False(t, bc.GetUnspent().Has(ux))
	}
}