Skip to content

Commit

Permalink
Merge pull request #330 from zhengq1/getunspent-for-every-address
Browse files Browse the repository at this point in the history
getunspent UTXO for every address / asset
  • Loading branch information
sharpbear authored Jul 10, 2017
2 parents 070b126 + c10ff44 commit 6f15a40
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 3 deletions.
2 changes: 2 additions & 0 deletions core/ledger/ledgerStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ type ILedgerStore interface {

GetUnspent(txid Uint256, index uint16) (*tx.TxOutput, error)
ContainsUnspent(txid Uint256, index uint16) (bool, error)
GetUnspentFromProgramHash(programHash Uint160, assetid Uint256) ([]*tx.UTXOUnspent, error)

IsTxHashDuplicate(txhash Uint256) bool
}
115 changes: 115 additions & 0 deletions core/store/ChainStore/ChainStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ func (self *ChainStore) GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey,
}

func (bd *ChainStore) persist(b *Block) error {
utxoUnspents := make(map[Uint160]map[Uint256][]*tx.UTXOUnspent)
unspents := make(map[Uint256][]uint16)
quantities := make(map[Uint256]Fixed64)

Expand Down Expand Up @@ -785,6 +786,25 @@ func (bd *ChainStore) persist(b *Block) error {
}
accounts[programHash] = accountState
}

// add utxoUnspent
if _, ok := utxoUnspents[programHash]; !ok {
utxoUnspents[programHash] = make(map[Uint256][]*tx.UTXOUnspent)
}

if _, ok := utxoUnspents[programHash][assetId]; !ok {
utxoUnspents[programHash][assetId], err = bd.GetUnspentFromProgramHash(programHash, assetId)
if err != nil {
utxoUnspents[programHash][assetId] = make([]*tx.UTXOUnspent, 0)
}
}

unspent := new(tx.UTXOUnspent)
unspent.Txid = b.Transactions[i].Hash()
unspent.Index = uint32(index)
unspent.Value = output.Value

utxoUnspents[programHash][assetId] = append(utxoUnspents[programHash][assetId], unspent)
}

for index := 0; index < len(b.Transactions[i].UTXOInputs); index++ {
Expand All @@ -810,6 +830,35 @@ func (bd *ChainStore) persist(b *Block) error {
if accounts[programHash].Balances[assetId] < 0 {
return errors.New(fmt.Sprintf("account programHash:%v, assetId:%v insufficient of balance", programHash, assetId))
}

// delete utxoUnspent
if _, ok := utxoUnspents[programHash]; !ok {
utxoUnspents[programHash] = make(map[Uint256][]*tx.UTXOUnspent)
}

if _, ok := utxoUnspents[programHash][assetId]; !ok {
utxoUnspents[programHash][assetId], err = bd.GetUnspentFromProgramHash(programHash, assetId)
if err != nil {
return errors.New(fmt.Sprintf("[persist] utxoUnspents programHash:%v, assetId:%v has no unspent UTXO.", programHash, assetId))
}
}

flag := false
listnum := len(utxoUnspents[programHash][assetId])
for i := 0; i < listnum; i++ {
if utxoUnspents[programHash][assetId][i].Txid.CompareTo(transaction.Hash()) == 0 && utxoUnspents[programHash][assetId][i].Index == uint32(index) {
utxoUnspents[programHash][assetId][i] = utxoUnspents[programHash][assetId][listnum-1]
utxoUnspents[programHash][assetId] = utxoUnspents[programHash][assetId][:listnum-1]

flag = true
break
}
}

if !flag {
return errors.New(fmt.Sprintf("[persist] utxoUnspents NOT find UTXO by txid: %x, index: %d.", transaction.Hash(), index))
}

}

// init unspent in tx
Expand Down Expand Up @@ -912,6 +961,16 @@ func (bd *ChainStore) persist(b *Block) error {
///////////////////////////////////////////////////////
//*/

// batch put the utxoUnspents
for programHash, programHash_value := range utxoUnspents {
for assetId, unspents := range programHash_value {
err := bd.saveUnspentWithProgramHash(programHash, assetId, unspents)
if err != nil {
return err
}
}
}

// batch put the unspents
for txhash, value := range unspents {
unspentKey := bytes.NewBuffer(nil)
Expand Down Expand Up @@ -1219,3 +1278,59 @@ func (bd *ChainStore) GetAccount(programHash Uint160) (*account.AccountState, er

return accountState, nil
}

func (bd *ChainStore) GetUnspentFromProgramHash(programHash Uint160, assetid Uint256) ([]*tx.UTXOUnspent, error) {

prefix := []byte{byte(IX_Unspent_UTXO)}

key := append(prefix, programHash.ToArray()...)
key = append(key, assetid.ToArray()...)
unspentsData, err := bd.st.Get(key)
if err != nil {
return nil, err
}

r := bytes.NewReader(unspentsData)
listNum, err := serialization.ReadVarUint(r, 0)
if err != nil {
return nil, err
}

//log.Trace(fmt.Printf("[getUnspentFromProgramHash] listNum: %d, unspentsData: %x\n", listNum, unspentsData ))

// read unspent list in store
unspents := make([]*tx.UTXOUnspent, listNum)
for i := 0; i < int(listNum); i++ {
uu := new(tx.UTXOUnspent)
err := uu.Deserialize(r)
if err != nil {
return nil, err
}

unspents[i] = uu
}

return unspents, nil
}

func (bd *ChainStore) saveUnspentWithProgramHash(programHash Uint160, assetid Uint256, unspents []*tx.UTXOUnspent) error {
prefix := []byte{byte(IX_Unspent_UTXO)}

key := append(prefix, programHash.ToArray()...)
key = append(key, assetid.ToArray()...)

listnum := len(unspents)
w := bytes.NewBuffer(nil)
serialization.WriteVarUint(w, uint64(listnum))
for i := 0; i < listnum; i++ {
unspents[i].Serialize(w)
}

// BATCH PUT VALUE
err := bd.st.BatchPut(key, w.Bytes())
if err != nil {
return err
}

return nil
}
6 changes: 3 additions & 3 deletions core/store/ChainStore/DataEntryPrefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
IX_HeaderHashList DataEntryPrefix = 0x80
IX_Enrollment DataEntryPrefix = 0x84
IX_Unspent DataEntryPrefix = 0x90
IX_Unclaimed DataEntryPrefix = 0x91
IX_Unspent_UTXO DataEntryPrefix = 0x91
IX_Vote DataEntryPrefix = 0x94

// ASSET
Expand All @@ -23,8 +23,8 @@ const (
ST_ACCOUNT DataEntryPrefix = 0xc2

//SYSTEM
SYS_CurrentBlock DataEntryPrefix = 0x40
SYS_CurrentHeader DataEntryPrefix = 0x41
SYS_CurrentBlock DataEntryPrefix = 0x40
SYS_CurrentHeader DataEntryPrefix = 0x41
SYS_CurrentBookKeeper DataEntryPrefix = 0x42

//CONFIG
Expand Down
33 changes: 33 additions & 0 deletions core/transaction/utxoUnspent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package transaction

import (
"DNA/common"
"DNA/common/serialization"
"io"
)

type UTXOUnspent struct {
Txid common.Uint256
Index uint32
Value common.Fixed64
}

func (uu *UTXOUnspent) Serialize(w io.Writer) {
uu.Txid.Serialize(w)
serialization.WriteUint32(w, uu.Index)
uu.Value.Serialize(w)
}

func (uu *UTXOUnspent) Deserialize(r io.Reader) error {
uu.Txid.Deserialize(r)

index, err := serialization.ReadUint32(r)
uu.Index = uint32(index)
if err != nil {
return err
}

uu.Value.Deserialize(r)

return nil
}

0 comments on commit 6f15a40

Please sign in to comment.