6 Star 46 Fork 28

Hyperledger/fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
pool.go 6.04 KB
一键复制 编辑 原始数据 按行查看 历史
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package plain
import (
"fmt"
"io"
"sync"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/protos/token"
"github.com/hyperledger/fabric/token/tms"
"github.com/pkg/errors"
)
// OutputNotFoundError is returned when an entry was not found in the pool.
type OutputNotFoundError struct {
ID string
}
func (o *OutputNotFoundError) Error() string {
return fmt.Sprintf("entry not found: %s", o.ID)
}
// TxNotFoundError is returned when a transaction was not found in the pool.
type TxNotFoundError struct {
TxID string
}
func (p *TxNotFoundError) Error() string {
return fmt.Sprintf("transaction not found: %s", p.TxID)
}
// A MemoryPool is an in-memory ledger of transactions and unspent outputs.
// This implementation is only meant for testing.
type MemoryPool struct {
mutex sync.RWMutex
entries map[string]*token.PlainOutput
history map[string]*token.TokenTransaction
}
// NewMemoryPool creates a new MemoryPool
func NewMemoryPool() *MemoryPool {
return &MemoryPool{
entries: map[string]*token.PlainOutput{},
history: map[string]*token.TokenTransaction{},
}
}
// Check if a proposed update can be committed.
func (p *MemoryPool) checkUpdate(transactionData []tms.TransactionData) error {
for _, td := range transactionData {
action := td.Tx.GetPlainAction()
if action == nil {
return errors.Errorf("check update failed for transaction '%s': missing token action", td.TxID)
}
err := p.checkAction(action, td.TxID)
if err != nil {
return errors.WithMessage(err, "check update failed")
}
if p.history[td.TxID] != nil {
return errors.Errorf("transaction already exists: %s", td.TxID)
}
}
return nil
}
// CommitUpdate commits transaction data into the pool.
func (p *MemoryPool) CommitUpdate(transactionData []tms.TransactionData) error {
p.mutex.Lock()
defer p.mutex.Unlock()
err := p.checkUpdate(transactionData)
if err != nil {
return err
}
for _, td := range transactionData {
p.commitAction(td.Tx.GetPlainAction(), td.TxID)
p.history[td.TxID] = cloneTransaction(td.Tx)
}
return nil
}
func (p *MemoryPool) checkAction(plainAction *token.PlainTokenAction, txID string) error {
switch action := plainAction.Data.(type) {
case *token.PlainTokenAction_PlainImport:
return p.checkImportAction(action.PlainImport, txID)
default:
return errors.Errorf("unknown plain token action: %T", action)
}
}
func (p *MemoryPool) commitAction(plainAction *token.PlainTokenAction, txID string) {
switch action := plainAction.Data.(type) {
case *token.PlainTokenAction_PlainImport:
p.commitImportAction(action.PlainImport, txID)
}
}
func (p *MemoryPool) checkImportAction(importAction *token.PlainImport, txID string) error {
for i := range importAction.GetOutputs() {
entryID := calculateOutputID(txID, i)
if p.entries[entryID] != nil {
return errors.Errorf("pool entry already exists: %s", entryID)
}
}
return nil
}
func (p *MemoryPool) commitImportAction(importAction *token.PlainImport, txID string) {
for i, entry := range importAction.GetOutputs() {
entryID := calculateOutputID(txID, i)
p.addEntry(entryID, entry)
}
}
// Add a new entry into the pool.
func (p *MemoryPool) addEntry(entryID string, entry *token.PlainOutput) {
p.entries[entryID] = cloneOutput(entry)
}
func cloneOutput(po *token.PlainOutput) *token.PlainOutput {
clone := proto.Clone(po)
return clone.(*token.PlainOutput)
}
func cloneTransaction(tt *token.TokenTransaction) *token.TokenTransaction {
clone := proto.Clone(tt)
return clone.(*token.TokenTransaction)
}
// OutputByID gets an output by its ID.
func (p *MemoryPool) OutputByID(id string) (*token.PlainOutput, error) {
p.mutex.RLock()
defer p.mutex.RUnlock()
output := p.entries[id]
if output == nil {
return nil, &OutputNotFoundError{ID: id}
}
return output, nil
}
// TxByID gets a transaction by its transaction ID.
// If no transaction exists with the given ID, a TxNotFoundError is returned.
func (p *MemoryPool) TxByID(txID string) (*token.TokenTransaction, error) {
p.mutex.RLock()
defer p.mutex.RUnlock()
tt := p.history[txID]
if tt == nil {
return nil, &TxNotFoundError{TxID: txID}
}
return tt, nil
}
// Iterator returns an iterator of the unspent outputs based on a copy of the pool.
func (p *MemoryPool) Iterator() *PoolIterator {
p.mutex.Lock()
defer p.mutex.Unlock()
keys := make([]string, len(p.entries))
i := 0
for k := range p.entries {
keys[i] = k
i++
}
return &PoolIterator{pool: p, keys: keys, current: 0}
}
// PoolIterator is an iterator for iterating through the items in the pool.
type PoolIterator struct {
pool *MemoryPool
keys []string
current int
}
// Next gets the next output from the pool, or io.EOF if there are no more outputs.
func (it *PoolIterator) Next() (string, *token.PlainOutput, error) {
if it.current >= len(it.keys) {
return "", nil, io.EOF
}
entryID := it.keys[it.current]
it.current++
entry, err := it.pool.OutputByID(entryID)
return entryID, entry, err
}
// HistoryIterator creates a new HistoryIterator for iterating through the transaction history.
func (p *MemoryPool) HistoryIterator() *HistoryIterator {
p.mutex.Lock()
defer p.mutex.Unlock()
keys := make([]string, len(p.history))
i := 0
for k := range p.history {
keys[i] = k
i++
}
return &HistoryIterator{pool: p, keys: keys, current: 0}
}
// HistoryIterator is an iterator for iterating through the transaction history.
type HistoryIterator struct {
pool *MemoryPool
keys []string
current int
}
// Next gets the next transaction from the history, or io.EOF if there are no more transactions.
func (it *HistoryIterator) Next() (string, *token.TokenTransaction, error) {
if it.current >= len(it.keys) {
return "", nil, io.EOF
}
txID := it.keys[it.current]
it.current++
tx, err := it.pool.TxByID(txID)
return txID, tx, err
}
// Calculate an ID for an individual output in a transaction, as a function of
// the transaction ID, and the index of the output
func calculateOutputID(tmsTxID string, index int) string {
return fmt.Sprintf("%s.%d", tmsTxID, index)
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/hyperledger/fabric.git
git@gitee.com:hyperledger/fabric.git
hyperledger
fabric
fabric
v1.4.1-rc1

搜索帮助