OSDN Git Service

stand tx is eveywhere (#298)
authorPaladz <yzhu101@uottawa.ca>
Thu, 18 Jan 2018 01:59:10 +0000 (09:59 +0800)
committerGitHub <noreply@github.com>
Thu, 18 Jan 2018 01:59:10 +0000 (09:59 +0800)
* stand tx is eveywhere

* add unit test

17 files changed:
blockchain/account/accounts.go
blockchain/account/builder.go
blockchain/account/receivers.go
blockchain/account/receivers_test.go
blockchain/control_programs.go [deleted file]
blockchain/receivers.go
blockchain/rpc_reactor.go
blockchain/txbuilder/actions.go
blockchain/txbuilder/types.go
cmd/bytomcli/commands/account.go
cmd/bytomcli/commands/bytomcli.go
mining/mining.go
protocol/patricia/patricia.go [deleted file]
protocol/patricia/patricia_test.go [deleted file]
protocol/state/utxo_view.go
protocol/state/utxo_view_test.go
protocol/vm/vmutil/script.go

index 02175ff..d21debe 100755 (executable)
@@ -228,18 +228,20 @@ func (m *Manager) GetAliasByID(id string) string {
        return account.Alias
 }
 
-// CreateAddress generate an address for the select account
 func (m *Manager) CreateAddress(ctx context.Context, accountID string, change bool) (cp *CtrlProgram, err error) {
        account, err := m.findByID(ctx, accountID)
        if err != nil {
                return nil, err
        }
+       return m.createAddress(ctx, account, change)
+}
 
-       expiresAt := time.Now().Add(defaultReceiverExpiry)
+// CreateAddress generate an address for the select account
+func (m *Manager) createAddress(ctx context.Context, account *Account, change bool) (cp *CtrlProgram, err error) {
        if len(account.XPubs) == 1 {
-               cp, err = m.createP2PKH(ctx, account, change, expiresAt)
+               cp, err = m.createP2PKH(ctx, account, change)
        } else {
-               cp, err = m.createP2SH(ctx, account, change, expiresAt)
+               cp, err = m.createP2SH(ctx, account, change)
        }
        if err != nil {
                return nil, err
@@ -251,7 +253,7 @@ func (m *Manager) CreateAddress(ctx context.Context, accountID string, change bo
        return cp, nil
 }
 
-func (m *Manager) createP2PKH(ctx context.Context, account *Account, change bool, expiresAt time.Time) (*CtrlProgram, error) {
+func (m *Manager) createP2PKH(ctx context.Context, account *Account, change bool) (*CtrlProgram, error) {
        idx := m.nextIndex()
        path := signers.Path(account.Signer, signers.AccountKeySpace, idx)
        derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path)
@@ -275,11 +277,10 @@ func (m *Manager) createP2PKH(ctx context.Context, account *Account, change bool
                KeyIndex:       idx,
                ControlProgram: control,
                Change:         change,
-               ExpiresAt:      expiresAt,
        }, nil
 }
 
-func (m *Manager) createP2SH(ctx context.Context, account *Account, change bool, expiresAt time.Time) (*CtrlProgram, error) {
+func (m *Manager) createP2SH(ctx context.Context, account *Account, change bool) (*CtrlProgram, error) {
        idx := m.nextIndex()
        path := signers.Path(account.Signer, signers.AccountKeySpace, idx)
        derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path)
@@ -307,48 +308,9 @@ func (m *Manager) createP2SH(ctx context.Context, account *Account, change bool,
                KeyIndex:       idx,
                ControlProgram: control,
                Change:         change,
-               ExpiresAt:      expiresAt,
        }, nil
 }
 
-func (m *Manager) createControlProgram(ctx context.Context, accountID string, change bool, expiresAt time.Time) (*CtrlProgram, error) {
-       account, err := m.findByID(ctx, accountID)
-       if err != nil {
-               return nil, err
-       }
-
-       idx := m.nextIndex()
-       path := signers.Path(account.Signer, signers.AccountKeySpace, idx)
-       derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path)
-       derivedPKs := chainkd.XPubKeys(derivedXPubs)
-       control, err := vmutil.P2SPMultiSigProgram(derivedPKs, account.Quorum)
-       if err != nil {
-               return nil, err
-       }
-
-       return &CtrlProgram{
-               AccountID:      account.ID,
-               KeyIndex:       idx,
-               ControlProgram: control,
-               Change:         change,
-               ExpiresAt:      expiresAt,
-       }, nil
-}
-
-// CreateControlProgram creates a control program
-// that is tied to the Account and stores it in the database.
-func (m *Manager) CreateControlProgram(ctx context.Context, accountID string, change bool, expiresAt time.Time) ([]byte, error) {
-       cp, err := m.createControlProgram(ctx, accountID, change, expiresAt)
-       if err != nil {
-               return nil, err
-       }
-
-       if err = m.insertAccountControlProgram(ctx, cp); err != nil {
-               return nil, err
-       }
-       return cp.ControlProgram, nil
-}
-
 //CtrlProgram is structure of account control program
 type CtrlProgram struct {
        AccountID      string
@@ -356,7 +318,6 @@ type CtrlProgram struct {
        KeyIndex       uint64
        ControlProgram []byte
        Change         bool
-       ExpiresAt      time.Time
 }
 
 func (m *Manager) insertAccountControlProgram(ctx context.Context, progs ...*CtrlProgram) error {
@@ -374,42 +335,25 @@ func (m *Manager) insertAccountControlProgram(ctx context.Context, progs ...*Ctr
 }
 
 // GetCoinbaseControlProgram will return a coinbase script
-func (m *Manager) GetCoinbaseControlProgram(height uint64) ([]byte, error) {
+func (m *Manager) GetCoinbaseControlProgram() ([]byte, error) {
        accountIter := m.db.IteratorPrefix([]byte(accountPrefix))
        defer accountIter.Release()
        if !accountIter.Next() {
                log.Warningf("GetCoinbaseControlProgram: can't find any account in db")
-               return vmutil.CoinbaseProgram(nil, 0, height)
+               return vmutil.DefaultCoinbaseProgram()
        }
        rawAccount := accountIter.Value()
 
        account := &Account{}
        if err := json.Unmarshal(rawAccount, account); err != nil {
-               log.Errorf("GetCoinbaseControlProgram: fail to unmarshal account %v", err)
-               return vmutil.CoinbaseProgram(nil, 0, height)
-       }
-
-       ctx := context.Background()
-       idx := m.nextIndex()
-       path := signers.Path(account.Signer, signers.AccountKeySpace, idx)
-       derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path)
-       derivedPKs := chainkd.XPubKeys(derivedXPubs)
-
-       script, err := vmutil.CoinbaseProgram(derivedPKs, account.Quorum, height)
-       if err != nil {
-               return script, err
+               return nil, err
        }
 
-       err = m.insertAccountControlProgram(ctx, &CtrlProgram{
-               AccountID:      account.ID,
-               KeyIndex:       idx,
-               ControlProgram: script,
-               Change:         false,
-       })
+       program, err := m.createAddress(nil, account, false)
        if err != nil {
-               log.Errorf("GetCoinbaseControlProgram: fail to insertAccountControlProgram %v", err)
+               return nil, err
        }
-       return script, nil
+       return program.ControlProgram, nil
 }
 
 func (m *Manager) nextIndex() uint64 {
index be1a7d8..bd7b452 100755 (executable)
@@ -74,7 +74,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
        }
 
        if res.Change > 0 {
-               acp, err := a.accounts.createControlProgram(ctx, a.AccountID, true, b.MaxTime())
+               acp, err := a.accounts.CreateAddress(ctx, a.AccountID, true)
                if err != nil {
                        return errors.Wrap(err, "creating control program")
                }
@@ -214,7 +214,7 @@ func (a *controlAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder)
        }
 
        // Produce a control program, but don't insert it into the database yet.
-       acp, err := a.accounts.createControlProgram(ctx, a.AccountID, false, b.MaxTime())
+       acp, err := a.accounts.CreateAddress(ctx, a.AccountID, false)
        if err != nil {
                return err
        }
index 0f9a84b..a4188a5 100755 (executable)
@@ -5,37 +5,10 @@ import (
        "time"
 
        "github.com/bytom/blockchain/txbuilder"
-       "github.com/bytom/errors"
 )
 
 const defaultReceiverExpiry = 30 * 24 * time.Hour // 30 days
 
-// CreateReceiver creates a new account receiver for an account
-// with the provided expiry. If a zero time is provided for the
-// expiry, a default expiry of 30 days from the current time is
-// used.
-func (m *Manager) CreateReceiver(ctx context.Context, accountInfo string) (*txbuilder.Receiver, error) {
-       expiresAt := time.Now().Add(defaultReceiverExpiry)
-
-       accountID := accountInfo
-
-       if s, err := m.FindByAlias(ctx, accountInfo); err == nil {
-               accountID = s.ID
-       }
-
-       cp, err := m.CreateControlProgram(ctx, accountID, false, expiresAt)
-       if err != nil {
-               return nil, errors.Wrap(err)
-       }
-
-       receiver := &txbuilder.Receiver{
-               ControlProgram: cp,
-               ExpiresAt:      expiresAt,
-       }
-
-       return receiver, nil
-}
-
 // CreateAddressReceiver creates a new address receiver for an account
 func (m *Manager) CreateAddressReceiver(ctx context.Context, accountInfo string) (*txbuilder.Receiver, error) {
        accountID := accountInfo
@@ -51,6 +24,5 @@ func (m *Manager) CreateAddressReceiver(ctx context.Context, accountInfo string)
        return &txbuilder.Receiver{
                ControlProgram: program.ControlProgram,
                Address:        program.Address,
-               ExpiresAt:      program.ExpiresAt,
        }, nil
 }
index 585c52d..fa5367c 100644 (file)
@@ -8,26 +8,6 @@ import (
        "github.com/bytom/testutil"
 )
 
-func TestCreateReceiver(t *testing.T) {
-       m := mockAccountManager(t)
-       ctx := context.Background()
-
-       account, err := m.Create([]chainkd.XPub{testutil.TestXPub}, 1, "test-alias", nil)
-       if err != nil {
-               testutil.FatalErr(t, err)
-       }
-
-       _, err = m.CreateReceiver(ctx, account.ID)
-       if err != nil {
-               testutil.FatalErr(t, err)
-       }
-
-       _, err = m.CreateReceiver(ctx, account.Alias)
-       if err != nil {
-               testutil.FatalErr(t, err)
-       }
-}
-
 func TestCreateAddressReceiver(t *testing.T) {
        m := mockAccountManager(t)
        ctx := context.Background()
diff --git a/blockchain/control_programs.go b/blockchain/control_programs.go
deleted file mode 100644 (file)
index 96628c0..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-package blockchain
-
-import (
-       "context"
-       stdjson "encoding/json"
-       "sync"
-       "time"
-
-       "github.com/bytom/encoding/json"
-       "github.com/bytom/errors"
-       "github.com/bytom/net/http/httpjson"
-       "github.com/bytom/net/http/reqid"
-)
-
-// POST /create-control-program
-func (bcr *BlockchainReactor) createControlProgram(ctx context.Context, ins []struct {
-       Type   string
-       Params stdjson.RawMessage
-}) interface{} {
-       responses := make([]interface{}, len(ins))
-       var wg sync.WaitGroup
-       wg.Add(len(responses))
-
-       for i := 0; i < len(responses); i++ {
-               go func(i int) {
-                       subctx := reqid.NewSubContext(ctx, reqid.New())
-                       defer wg.Done()
-                       defer batchRecover(subctx, &responses[i])
-
-                       var (
-                               prog interface{}
-                               err  error
-                       )
-                       switch ins[i].Type {
-                       case "account":
-                               prog, err = bcr.createAccountControlProgram(subctx, ins[i].Params)
-                       default:
-                               err = errors.WithDetailf(httpjson.ErrBadRequest, "unknown control program type %q", ins[i].Type)
-                       }
-                       if err != nil {
-                               responses[i] = err
-                       } else {
-                               responses[i] = prog
-                       }
-               }(i)
-       }
-
-       wg.Wait()
-       return responses
-}
-
-func (bcr *BlockchainReactor) createAccountControlProgram(ctx context.Context, input []byte) (interface{}, error) {
-       var parsed struct {
-               AccountAlias string `json:"account_alias"`
-               AccountID    string `json:"account_id"`
-       }
-       err := stdjson.Unmarshal(input, &parsed)
-       if err != nil {
-               return nil, errors.WithDetailf(httpjson.ErrBadRequest, "bad parameters for account control program")
-       }
-
-       accountID := parsed.AccountID
-       if accountID == "" {
-               acc, err := bcr.accounts.FindByAlias(ctx, parsed.AccountAlias)
-               if err != nil {
-                       return nil, err
-               }
-               accountID = acc.ID
-       }
-
-       controlProgram, err := bcr.accounts.CreateControlProgram(ctx, accountID, false, time.Time{})
-       if err != nil {
-               return nil, err
-       }
-
-       ret := map[string]interface{}{
-               "control_program": json.HexBytes(controlProgram),
-       }
-       return ret, nil
-}
index ccda8de..8ab958e 100755 (executable)
@@ -4,20 +4,8 @@ import (
        "context"
 )
 
-// POST /create-account-receiver
-func (bcr *BlockchainReactor) createAccountReceiver(ctx context.Context, ins struct {
-       AccountInfo string    `json:"account_info"`
-}) Response {
-       receiver, err := bcr.accounts.CreateReceiver(nil, ins.AccountInfo)
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-
-       return NewSuccessResponse(*receiver)
-}
-
 func (bcr *BlockchainReactor) createAccountAddress(ctx context.Context, ins struct {
-       AccountInfo string    `json:"account_info"`
+       AccountInfo string `json:"account_info"`
 }) Response {
        receiver, err := bcr.accounts.CreateAddressReceiver(ctx, ins.AccountInfo)
        if err != nil {
index 84c0254..6626d18 100644 (file)
@@ -54,7 +54,6 @@ func (bcr *BlockchainReactor) BuildHandler() {
        if bcr.accounts != nil && bcr.assets != nil {
                m.Handle("/create-account", jsonHandler(bcr.createAccount))
                m.Handle("/update-account-tags", jsonHandler(bcr.updateAccountTags))
-               m.Handle("/create-account-receiver", jsonHandler(bcr.createAccountReceiver))
                m.Handle("/create-account-address", jsonHandler(bcr.createAccountAddress))
                m.Handle("/list-accounts", jsonHandler(bcr.listAccounts))
                m.Handle("/delete-account", jsonHandler(bcr.deleteAccount))
@@ -81,7 +80,6 @@ func (bcr *BlockchainReactor) BuildHandler() {
        m.Handle("/submit-transaction", jsonHandler(bcr.submit))
        m.Handle("/sign-submit-transaction", jsonHandler(bcr.signSubmit))
 
-       m.Handle("/create-control-program", jsonHandler(bcr.createControlProgram))
        m.Handle("/create-transaction-feed", jsonHandler(bcr.createTxFeed))
        m.Handle("/get-transaction-feed", jsonHandler(bcr.getTxFeed))
        m.Handle("/update-transaction-feed", jsonHandler(bcr.updateTxFeed))
index 96a0779..066ceef 100644 (file)
@@ -37,9 +37,6 @@ func (a *controlReceiverAction) Build(ctx context.Context, b *TemplateBuilder) e
                if len(a.Receiver.ControlProgram) == 0 {
                        missing = append(missing, "receiver.control_program")
                }
-               if a.Receiver.ExpiresAt.IsZero() {
-                       missing = append(missing, "receiver.expires_at")
-               }
        }
        if a.AssetId.IsZero() {
                missing = append(missing, "asset_id")
@@ -48,7 +45,6 @@ func (a *controlReceiverAction) Build(ctx context.Context, b *TemplateBuilder) e
                return MissingFieldsError(missing...)
        }
 
-       b.RestrictMaxTime(a.Receiver.ExpiresAt)
        out := legacy.NewTxOutput(*a.AssetId, a.Amount, a.Receiver.ControlProgram, a.ReferenceData)
        return b.AddOutput(out)
 }
index f764db5..2ebf1b5 100755 (executable)
@@ -2,7 +2,6 @@ package txbuilder
 
 import (
        "context"
-       "time"
 
        chainjson "github.com/bytom/encoding/json"
        "github.com/bytom/protocol/bc"
@@ -40,5 +39,4 @@ type Action interface {
 type Receiver struct {
        ControlProgram chainjson.HexBytes `json:"control_program,omitempty"`
        Address        string             `json:"address,omitempty"`
-       ExpiresAt      time.Time          `json:"expires_at"`
 }
index 91b81c8..e07a07b 100755 (executable)
@@ -138,25 +138,6 @@ var updateAccountTagsCmd = &cobra.Command{
        },
 }
 
-var createAccountReceiverCmd = &cobra.Command{
-       Use:   "create-account-receiver <accountID | alias>",
-       Short: "Create an account receiver control program",
-       Args:  cobra.ExactArgs(1),
-       Run: func(cmd *cobra.Command, args []string) {
-               var ins = struct {
-                       AccountInfo string    `json:"account_info"`
-                       ExpiresAt   time.Time `json:"expires_at,omitempty"`
-               }{AccountInfo: args[0]}
-
-               data, exitCode := util.ClientCall("/create-account-receiver", &ins)
-               if exitCode != util.Success {
-                       os.Exit(exitCode)
-               }
-
-               printJSON(data)
-       },
-}
-
 var createAccountAddressCmd = &cobra.Command{
        Use:   "create-account-address <accountID | alias>",
        Short: "Create an account address",
index 6e7b01c..26c5501 100644 (file)
@@ -82,7 +82,6 @@ func AddCommands() {
        BytomcliCmd.AddCommand(deleteAccountCmd)
        BytomcliCmd.AddCommand(listAccountsCmd)
        BytomcliCmd.AddCommand(updateAccountTagsCmd)
-       BytomcliCmd.AddCommand(createAccountReceiverCmd)
        BytomcliCmd.AddCommand(createAccountAddressCmd)
 
        BytomcliCmd.AddCommand(createAssetCmd)
@@ -129,5 +128,3 @@ func AddCommands() {
 
        BytomcliCmd.AddCommand(versionCmd)
 }
-
-
index ef78ce0..42d1a6e 100644 (file)
@@ -28,13 +28,12 @@ import (
 // is nil, the coinbase transaction will instead be redeemable by anyone.
 func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeight uint64) (tx *legacy.Tx, err error) {
        amount += consensus.BlockSubsidy(blockHeight)
-       unlockHeight := blockHeight + consensus.CoinbasePendingBlockNumber
 
        var script []byte
        if accountManager == nil {
-               script, err = vmutil.CoinbaseProgram(nil, 0, unlockHeight)
+               script, err = vmutil.DefaultCoinbaseProgram()
        } else {
-               script, err = accountManager.GetCoinbaseControlProgram(unlockHeight)
+               script, err = accountManager.GetCoinbaseControlProgram()
        }
        if err != nil {
                return
diff --git a/protocol/patricia/patricia.go b/protocol/patricia/patricia.go
deleted file mode 100644 (file)
index 1e0cba6..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-// Package patricia computes the Merkle Patricia Tree Hash of a
-// set of bit strings, as described in the Chain Protocol spec.
-// See https://chain.com/docs/protocol/specifications/data#merkle-patricia-tree.
-// Because a patricia tree (a radix tree with a radix of 2)
-// provides efficient incremental updates, so does the Merkle
-// Patricia Tree Hash computation, making this structure suitable
-// for the blockchain full-state commitment.
-//
-// Type Tree represents a set, where the elements are bit strings.
-// The set must be prefix-free -- no item can be a prefix of
-// any other -- enforced by Insert.
-// The length of each bit string must also be a multiple of eight,
-// because the interface uses []byte to represent an item.
-//
-// The nodes in the tree form an immutable persistent data
-// structure. It is okay to copy a Tree struct,
-// which contains the root of the tree, to obtain a new tree
-// with the same contents. The time to make such a copy is
-// independent of the size of the tree.
-package patricia
-
-import (
-       "bytes"
-
-       "github.com/bytom/crypto/sha3pool"
-       "github.com/bytom/errors"
-       "github.com/bytom/protocol/bc"
-)
-
-var (
-       leafPrefix     = []byte{0x00}
-       interiorPrefix = []byte{0x01}
-)
-
-// Tree implements a patricia tree.
-type Tree struct {
-       root *node
-}
-
-// WalkFunc is the type of the function called for each item
-// visited by Walk. If an error is returned, processing stops.
-type WalkFunc func(item []byte) error
-
-// Walk walks t calling walkFn for each item.
-// If an error is returned by walkFn at any point,
-// processing is stopped and the error is returned.
-func Walk(t *Tree, walkFn WalkFunc) error {
-       if t.root == nil {
-               return nil
-       }
-       return walk(t.root, walkFn)
-}
-
-func walk(n *node, walkFn WalkFunc) error {
-       if n.isLeaf {
-               return walkFn(n.Key())
-       }
-
-       if err := walk(n.children[0], walkFn); err != nil {
-               return err
-       }
-
-       err := walk(n.children[1], walkFn)
-       return err
-}
-
-// Contains returns whether t contains item.
-func (t *Tree) Contains(item []byte) bool {
-       if t.root == nil {
-               return false
-       }
-
-       key := bitKey(item)
-       n := lookup(t.root, key)
-
-       var hash bc.Hash
-       h := sha3pool.Get256()
-       h.Write(leafPrefix)
-       h.Write(item)
-       hash.ReadFrom(h)
-       sha3pool.Put256(h)
-       return n != nil && n.Hash() == hash
-}
-
-func lookup(n *node, key []uint8) *node {
-       if bytes.Equal(n.key, key) {
-               if !n.isLeaf {
-                       return nil
-               }
-               return n
-       }
-       if !bytes.HasPrefix(key, n.key) {
-               return nil
-       }
-
-       bit := key[len(n.key)]
-       return lookup(n.children[bit], key)
-}
-
-// Insert inserts item into t.
-//
-// It is an error for item to be a prefix of an element
-// in t or to contain an element in t as a prefix.
-// If item itself is already in t, Insert does nothing
-// (and this is not an error).
-func (t *Tree) Insert(item []byte) (err error) {
-       key := bitKey(item)
-
-       var hash bc.Hash
-       h := sha3pool.Get256()
-       h.Write(leafPrefix)
-       h.Write(item)
-       hash.ReadFrom(h)
-       sha3pool.Put256(h)
-
-       if t.root == nil {
-               t.root = &node{key: key, hash: &hash, isLeaf: true}
-               return nil
-       }
-
-       t.root, err = insert(t.root, key, &hash)
-       return err
-}
-
-func insert(n *node, key []uint8, hash *bc.Hash) (*node, error) {
-       if bytes.Equal(n.key, key) {
-               if !n.isLeaf {
-                       return n, errors.Wrap(errors.New("key provided is a prefix to other keys"))
-               }
-
-               n = &node{
-                       isLeaf: true,
-                       key:    n.key,
-                       hash:   hash,
-               }
-               return n, nil
-       }
-
-       if bytes.HasPrefix(key, n.key) {
-               if n.isLeaf {
-                       return n, errors.Wrap(errors.New("key provided is a prefix to other keys"))
-               }
-               bit := key[len(n.key)]
-
-               child := n.children[bit]
-               child, err := insert(child, key, hash)
-               if err != nil {
-                       return n, err
-               }
-               newNode := new(node)
-               *newNode = *n
-               newNode.children[bit] = child // mutation is ok because newNode hasn't escaped yet
-               newNode.hash = nil
-               return newNode, nil
-       }
-
-       common := commonPrefixLen(n.key, key)
-       newNode := &node{
-               key: key[:common],
-       }
-       newNode.children[key[common]] = &node{
-               key:    key,
-               hash:   hash,
-               isLeaf: true,
-       }
-       newNode.children[1-key[common]] = n
-       return newNode, nil
-}
-
-// Delete removes item from t, if present.
-func (t *Tree) Delete(item []byte) {
-       key := bitKey(item)
-
-       if t.root != nil {
-               t.root = delete(t.root, key)
-       }
-}
-
-func delete(n *node, key []uint8) *node {
-       if bytes.Equal(key, n.key) {
-               if !n.isLeaf {
-                       return n
-               }
-               return nil
-       }
-
-       if !bytes.HasPrefix(key, n.key) {
-               return n
-       }
-
-       bit := key[len(n.key)]
-       newChild := delete(n.children[bit], key)
-
-       if newChild == nil {
-               return n.children[1-bit]
-       }
-
-       newNode := new(node)
-       *newNode = *n
-       newNode.key = newChild.key[:len(n.key)] // only use slices of leaf node keys
-       newNode.children[bit] = newChild
-       newNode.hash = nil
-
-       return newNode
-}
-
-// RootHash returns the Merkle root of the tree.
-func (t *Tree) RootHash() bc.Hash {
-       root := t.root
-       if root == nil {
-               return bc.Hash{}
-       }
-       return root.Hash()
-}
-
-// bitKey takes a byte array and returns a key that can
-// be used inside insert and delete operations.
-func bitKey(byteKey []byte) []uint8 {
-       key := make([]uint8, 0, len(byteKey)*8)
-       for _, b := range byteKey {
-               for i := uint(0); i < 8; i++ {
-                       key = append(key, (b>>(7-i))&1)
-               }
-       }
-       return key
-}
-
-// byteKey is the inverse of bitKey.
-func byteKey(bitKey []uint8) (key []byte) {
-       key = make([]byte, len(bitKey)/8)
-       for i := uint(0); i < uint(len(key)); i++ {
-               var b byte
-               for j := uint(0); j < 8; j++ {
-                       bit := bitKey[i*8+j]
-                       b |= bit << (7 - j)
-               }
-               key[i] = b
-       }
-       return key
-}
-
-func commonPrefixLen(a, b []uint8) int {
-       var common int
-       for i := 0; i < len(a) && i < len(b); i++ {
-               if a[i] != b[i] {
-                       break
-               }
-               common++
-       }
-       return common
-}
-
-// node is a leaf or branch node in a tree
-type node struct {
-       key      []uint8
-       hash     *bc.Hash
-       isLeaf   bool
-       children [2]*node
-}
-
-// Key returns the key for the current node as bytes, as it
-// was provided to Insert.
-func (n *node) Key() []byte { return byteKey(n.key) }
-
-// Hash will return the hash for this node.
-func (n *node) Hash() bc.Hash {
-       n.calcHash()
-       return *n.hash
-}
-
-func (n *node) calcHash() {
-       if n.hash != nil {
-               return
-       }
-
-       h := sha3pool.Get256()
-       h.Write(interiorPrefix)
-       for _, c := range n.children {
-               c.calcHash()
-               c.hash.WriteTo(h)
-       }
-
-       var hash bc.Hash
-       hash.ReadFrom(h)
-       n.hash = &hash
-       sha3pool.Put256(h)
-}
diff --git a/protocol/patricia/patricia_test.go b/protocol/patricia/patricia_test.go
deleted file mode 100644 (file)
index 1c423e6..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-package patricia
-
-import (
-       "fmt"
-       "log"
-       "math/rand"
-       "strconv"
-       "strings"
-       "testing"
-       "testing/quick"
-
-       "golang.org/x/crypto/sha3"
-
-       "github.com/bytom/protocol/bc"
-       "github.com/bytom/testutil"
-)
-
-func BenchmarkInserts(b *testing.B) {
-       const nodes = 10000
-       for i := 0; i < b.N; i++ {
-               r := rand.New(rand.NewSource(12345))
-               tr := new(Tree)
-               for j := 0; j < nodes; j++ {
-                       var h [32]byte
-                       _, err := r.Read(h[:])
-                       if err != nil {
-                               b.Fatal(err)
-                       }
-
-                       err = tr.Insert(h[:])
-                       if err != nil {
-                               b.Fatal(err)
-                       }
-               }
-       }
-}
-
-func BenchmarkInsertsRootHash(b *testing.B) {
-       const nodes = 10000
-       for i := 0; i < b.N; i++ {
-               r := rand.New(rand.NewSource(12345))
-               tr := new(Tree)
-               for j := 0; j < nodes; j++ {
-                       var h [32]byte
-                       _, err := r.Read(h[:])
-                       if err != nil {
-                               b.Fatal(err)
-                       }
-
-                       err = tr.Insert(h[:])
-                       if err != nil {
-                               b.Fatal(err)
-                       }
-               }
-               tr.RootHash()
-       }
-}
-
-func TestRootHashBug(t *testing.T) {
-       tr := new(Tree)
-
-       err := tr.Insert([]byte{0x94})
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = tr.Insert([]byte{0x36})
-       if err != nil {
-               t.Fatal(err)
-       }
-       before := tr.RootHash()
-       err = tr.Insert([]byte{0xba})
-       if err != nil {
-               t.Fatal(err)
-       }
-       if tr.RootHash() == before {
-               t.Errorf("before and after root hash is %s", before.String())
-       }
-}
-
-func TestLeafVsInternalNodes(t *testing.T) {
-       tr0 := new(Tree)
-
-       err := tr0.Insert([]byte{0x01})
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = tr0.Insert([]byte{0x02})
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = tr0.Insert([]byte{0x03})
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = tr0.Insert([]byte{0x04})
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       // Force calculation of all the hashes.
-       tr0.RootHash()
-       t.Logf("first child = %s, %t", tr0.root.children[0].hash, tr0.root.children[0].isLeaf)
-       t.Logf("second child = %s, %t", tr0.root.children[1].hash, tr0.root.children[1].isLeaf)
-
-       // Create a second tree using an internal node from tr1.
-       tr1 := new(Tree)
-       err = tr1.Insert(tr0.root.children[0].hash.Bytes()) // internal node of tr0
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = tr1.Insert(tr0.root.children[1].hash.Bytes()) // sibling leaf node of above node ^
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       if tr1.RootHash() == tr0.RootHash() {
-               t.Errorf("tr0 and tr1 have matching root hashes: %x", tr1.RootHash().Bytes())
-       }
-}
-
-func TestRootHashInsertQuickCheck(t *testing.T) {
-       tr := new(Tree)
-
-       f := func(b [32]byte) bool {
-               before := tr.RootHash()
-               err := tr.Insert(b[:])
-               if err != nil {
-                       return false
-               }
-               return before != tr.RootHash()
-       }
-       if err := quick.Check(f, nil); err != nil {
-               t.Error(err)
-       }
-}
-
-func TestLookup(t *testing.T) {
-       tr := &Tree{
-               root: &node{key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-       }
-       got := lookup(tr.root, bitKey(bits("11111111")))
-       if !testutil.DeepEqual(got, tr.root) {
-               t.Log("lookup on 1-node tree")
-               t.Fatalf("got:\n%swant:\n%s", prettyNode(got, 0), prettyNode(tr.root, 0))
-       }
-
-       tr = &Tree{
-               root: &node{key: bools("11111110"), hash: hashPtr(hashForLeaf(bits("11111110"))), isLeaf: true},
-       }
-       got = lookup(tr.root, bitKey(bits("11111111")))
-       if got != nil {
-               t.Log("lookup nonexistent key on 1-node tree")
-               t.Fatalf("got:\n%swant nil", prettyNode(got, 0))
-       }
-
-       tr = &Tree{
-               root: &node{
-                       key:  bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11110000")), hashForLeaf(bits("11111111")))),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                       },
-               },
-       }
-       got = lookup(tr.root, bitKey(bits("11110000")))
-       if !testutil.DeepEqual(got, tr.root.children[0]) {
-               t.Log("lookup root's first child")
-               t.Fatalf("got:\n%swant:\n%s", prettyNode(got, 0), prettyNode(tr.root.children[0], 0))
-       }
-
-       tr = &Tree{
-               root: &node{
-                       key: bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(
-                               hashForLeaf(bits("11110000")),
-                               hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111"))),
-                       )),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {
-                                       key:  bools("111111"),
-                                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111")))),
-                                       children: [2]*node{
-                                               {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                       },
-                               },
-                       },
-               },
-       }
-       got = lookup(tr.root, bitKey(bits("11111100")))
-       if !testutil.DeepEqual(got, tr.root.children[1].children[0]) {
-               t.Fatalf("got:\n%swant:\n%s", prettyNode(got, 0), prettyNode(tr.root.children[1].children[0], 0))
-       }
-}
-
-func TestContains(t *testing.T) {
-       tr := new(Tree)
-       tr.Insert(bits("00000011"))
-       tr.Insert(bits("00000010"))
-
-       if v := bits("00000011"); !tr.Contains(v) {
-               t.Errorf("expected tree to contain %x, but did not", v)
-       }
-       if v := bits("00000000"); tr.Contains(v) {
-               t.Errorf("expected tree to not contain %x, but did", v)
-       }
-       if v := bits("00000010"); !tr.Contains(v) {
-               t.Errorf("expected tree to contain %x, but did not", v)
-       }
-}
-
-func TestInsert(t *testing.T) {
-       tr := new(Tree)
-
-       tr.Insert(bits("11111111"))
-       tr.RootHash()
-       want := &Tree{
-               root: &node{key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               log.Printf("want hash? %x", hashForLeaf(bits("11111111")).Bytes())
-               t.Log("insert into empty tree")
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Insert(bits("11111111"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Log("inserting the same key does not modify the tree")
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Insert(bits("11110000"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{
-                       key:  bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11110000")), hashForLeaf(bits("11111111")))),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Log("different key creates a fork")
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Insert(bits("11111100"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{
-                       key: bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(
-                               hashForLeaf(bits("11110000")),
-                               hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111"))),
-                       )),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {
-                                       key:  bools("111111"),
-                                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111")))),
-                                       children: [2]*node{
-                                               {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                       },
-                               },
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Insert(bits("11111110"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{
-                       key: bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(
-                               hashForLeaf(bits("11110000")),
-                               hashForNonLeaf(
-                                       hashForLeaf(bits("11111100")),
-                                       hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                               ),
-                       )),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {
-                                       key: bools("111111"),
-                                       hash: hashPtr(hashForNonLeaf(
-                                               hashForLeaf(bits("11111100")),
-                                               hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))))),
-                                       children: [2]*node{
-                                               {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                               {
-                                                       key:  bools("1111111"),
-                                                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111")))),
-                                                       children: [2]*node{
-                                                               {key: bools("11111110"), hash: hashPtr(hashForLeaf(bits("11111110"))), isLeaf: true},
-                                                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                                       },
-                                               },
-                                       },
-                               },
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Log("a fork is created for each level of similar key")
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Insert(bits("11111011"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{
-                       key: bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(
-                               hashForLeaf(bits("11110000")),
-                               hashForNonLeaf(
-                                       hashForLeaf(bits("11111011")),
-                                       hashForNonLeaf(
-                                               hashForLeaf(bits("11111100")),
-                                               hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                                       ),
-                               ),
-                       )),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {
-                                       key: bools("11111"),
-                                       hash: hashPtr(hashForNonLeaf(
-                                               hashForLeaf(bits("11111011")),
-                                               hashForNonLeaf(
-                                                       hashForLeaf(bits("11111100")),
-                                                       hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                                               ))),
-                                       children: [2]*node{
-                                               {key: bools("11111011"), hash: hashPtr(hashForLeaf(bits("11111011"))), isLeaf: true},
-                                               {
-                                                       key: bools("111111"),
-                                                       hash: hashPtr(hashForNonLeaf(
-                                                               hashForLeaf(bits("11111100")),
-                                                               hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                                                       )),
-                                                       children: [2]*node{
-                                                               {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                                               {
-                                                                       key:  bools("1111111"),
-                                                                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111")))),
-                                                                       children: [2]*node{
-                                                                               {key: bools("11111110"), hash: hashPtr(hashForLeaf(bits("11111110"))), isLeaf: true},
-                                                                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                                                       },
-                                                               },
-                                                       },
-                                               },
-                                       },
-                               },
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Log("compressed branch node is split")
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-}
-
-func TestDelete(t *testing.T) {
-       tr := new(Tree)
-       tr.root = &node{
-               key: bools("1111"),
-               hash: hashPtr(hashForNonLeaf(
-                       hashForLeaf(bits("11110000")),
-                       hashForNonLeaf(
-                               hashForLeaf(bits("11111100")),
-                               hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                       ),
-               )),
-               children: [2]*node{
-                       {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                       {
-                               key: bools("111111"),
-                               hash: hashPtr(hashForNonLeaf(
-                                       hashForLeaf(bits("11111100")),
-                                       hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111"))),
-                               )),
-                               children: [2]*node{
-                                       {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                       {
-                                               key:  bools("1111111"),
-                                               hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111")))),
-                                               children: [2]*node{
-                                                       {key: bools("11111110"), hash: hashPtr(hashForLeaf(bits("11111110"))), isLeaf: true},
-                                                       {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                               },
-                                       },
-                               },
-                       },
-               },
-       }
-
-       tr.Delete(bits("11111110"))
-       tr.RootHash()
-       want := &Tree{
-               root: &node{
-                       key: bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(
-                               hashForLeaf(bits("11110000")),
-                               hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111"))),
-                       )),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {
-                                       key:  bools("111111"),
-                                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111100")), hashForLeaf(bits("11111111")))),
-                                       children: [2]*node{
-                                               {key: bools("11111100"), hash: hashPtr(hashForLeaf(bits("11111100"))), isLeaf: true},
-                                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                                       },
-                               },
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Delete(bits("11111100"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{
-                       key:  bools("1111"),
-                       hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11110000")), hashForLeaf(bits("11111111")))),
-                       children: [2]*node{
-                               {key: bools("11110000"), hash: hashPtr(hashForLeaf(bits("11110000"))), isLeaf: true},
-                               {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-                       },
-               },
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Delete(bits("11110011")) // nonexistent value
-       tr.RootHash()
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Delete(bits("11110000"))
-       tr.RootHash()
-       want = &Tree{
-               root: &node{key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-       }
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-
-       tr.Delete(bits("11111111"))
-       tr.RootHash()
-       want = &Tree{}
-       if !testutil.DeepEqual(tr.root, want.root) {
-               t.Fatalf("got:\n%swant:\n%s", pretty(tr), pretty(want))
-       }
-}
-
-func TestDeletePrefix(t *testing.T) {
-       root := &node{
-               key:  bools("111111"),
-               hash: hashPtr(hashForNonLeaf(hashForLeaf(bits("11111110")), hashForLeaf(bits("11111111")))),
-               children: [2]*node{
-                       {key: bools("11111110"), hash: hashPtr(hashForLeaf(bits("11111110"))), isLeaf: true},
-                       {key: bools("11111111"), hash: hashPtr(hashForLeaf(bits("11111111"))), isLeaf: true},
-               },
-       }
-
-       got := delete(root, bools("111111"))
-       got.calcHash()
-       if !testutil.DeepEqual(got, root) {
-               t.Fatalf("got:\n%swant:\n%s", prettyNode(got, 0), prettyNode(root, 0))
-       }
-}
-
-func TestBoolKey(t *testing.T) {
-       cases := []struct {
-               b []byte
-               w []uint8
-       }{{
-               b: nil,
-               w: []uint8{},
-       }, {
-               b: []byte{0x8f},
-               w: []uint8{1, 0, 0, 0, 1, 1, 1, 1},
-       }, {
-               b: []byte{0x81},
-               w: []uint8{1, 0, 0, 0, 0, 0, 0, 1},
-       }}
-
-       for _, c := range cases {
-               g := bitKey(c.b)
-
-               if !testutil.DeepEqual(g, c.w) {
-                       t.Errorf("Key(0x%x) = %v want %v", c.b, g, c.w)
-               }
-       }
-}
-
-func TestByteKey(t *testing.T) {
-       cases := []struct {
-               b []uint8
-               w []byte
-       }{{
-               b: []uint8{},
-               w: []byte{},
-       }, {
-               b: []uint8{1, 0, 0, 0, 1, 1, 1, 1},
-               w: []byte{0x8f},
-       }, {
-               b: []uint8{1, 0, 0, 0, 0, 0, 0, 1},
-               w: []byte{0x81},
-       }, {
-               b: []uint8{1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1},
-               w: []byte{0x81, 0x8f},
-       }}
-
-       for _, c := range cases {
-               g := byteKey(c.b)
-
-               if !testutil.DeepEqual(g, c.w) {
-                       t.Errorf("byteKey(%#v) = %x want %x", c.b, g, c.w)
-               }
-       }
-}
-
-func pretty(t *Tree) string {
-       if t.root == nil {
-               return ""
-       }
-       return prettyNode(t.root, 0)
-}
-
-func prettyNode(n *node, depth int) string {
-       prettyStr := strings.Repeat("  ", depth)
-       if n == nil {
-               prettyStr += "nil\n"
-               return prettyStr
-       }
-       var b int
-       if len(n.key) > 31*8 {
-               b = 31 * 8
-       }
-       prettyStr += fmt.Sprintf("key=%+v", n.key[b:])
-       if n.hash != nil {
-               prettyStr += fmt.Sprintf(" hash=%+v", n.hash)
-       }
-       prettyStr += "\n"
-
-       for _, c := range n.children {
-               if c != nil {
-                       prettyStr += prettyNode(c, depth+1)
-               }
-       }
-
-       return prettyStr
-}
-
-func bits(lit string) []byte {
-       var b [31]byte
-       n, _ := strconv.ParseUint(lit, 2, 8)
-       return append(b[:], byte(n))
-}
-
-func bools(lit string) []uint8 {
-       b := bitKey(bits(lit))
-       return append(b[:31*8], b[32*8-len(lit):]...)
-}
-
-func hashForLeaf(item []byte) bc.Hash {
-       return bc.NewHash(sha3.Sum256(append([]byte{0x00}, item...)))
-}
-
-func hashForNonLeaf(a, b bc.Hash) bc.Hash {
-       d := []byte{0x01}
-       d = append(d, a.Bytes()...)
-       d = append(d, b.Bytes()...)
-       return bc.NewHash(sha3.Sum256(d))
-}
-
-func hashPtr(h bc.Hash) *bc.Hash {
-       return &h
-}
index ddd5141..c9e2015 100644 (file)
@@ -4,6 +4,7 @@ import (
        "errors"
 
        "github.com/bytom/blockchain/txdb/storage"
+       "github.com/bytom/consensus"
        "github.com/bytom/protocol/bc"
 )
 
@@ -33,6 +34,9 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx) error {
                if entry.Spent {
                        return errors.New("utxo has been spent")
                }
+               if entry.IsCoinBase && entry.BlockHeight+consensus.CoinbasePendingBlockNumber > block.Height {
+                       return errors.New("coinbase utxo is not ready for use")
+               }
                entry.SpendOutput()
        }
 
index 296cbbb..237a4f8 100644 (file)
@@ -71,6 +71,62 @@ func TestApplyBlock(t *testing.T) {
                        },
                        err: false,
                },
+               {
+                       block: &bc.Block{
+                               BlockHeader: &bc.BlockHeader{
+                                       Height: 7,
+                               },
+                               Transactions: []*bc.Tx{
+                                       &bc.Tx{
+                                               TxHeader: &bc.TxHeader{
+                                                       ResultIds: []*bc.Hash{},
+                                               },
+                                               SpentOutputIDs: []bc.Hash{
+                                                       bc.Hash{V0: 0},
+                                               },
+                                       },
+                               },
+                       },
+                       inputView: &UtxoViewpoint{
+                               Entries: map[bc.Hash]*storage.UtxoEntry{
+                                       bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, false),
+                               },
+                       },
+                       fetchView: &UtxoViewpoint{
+                               Entries: map[bc.Hash]*storage.UtxoEntry{
+                                       bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, true),
+                               },
+                       },
+                       err: false,
+               },
+               {
+                       block: &bc.Block{
+                               BlockHeader: &bc.BlockHeader{
+                                       Height: 0,
+                               },
+                               Transactions: []*bc.Tx{
+                                       &bc.Tx{
+                                               TxHeader: &bc.TxHeader{
+                                                       ResultIds: []*bc.Hash{},
+                                               },
+                                               SpentOutputIDs: []bc.Hash{
+                                                       bc.Hash{V0: 0},
+                                               },
+                                       },
+                               },
+                       },
+                       inputView: &UtxoViewpoint{
+                               Entries: map[bc.Hash]*storage.UtxoEntry{
+                                       bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, false),
+                               },
+                       },
+                       fetchView: &UtxoViewpoint{
+                               Entries: map[bc.Hash]*storage.UtxoEntry{
+                                       bc.Hash{V0: 0}: storage.NewUtxoEntry(true, 0, true),
+                               },
+                       },
+                       err: true,
+               },
        }
 
        for i, c := range cases {
index 2e5627f..a3fcd1a 100644 (file)
@@ -35,20 +35,10 @@ func (b *Builder) addP2SPMultiSig(pubkeys []ed25519.PublicKey, nrequired int) er
        return nil
 }
 
-// CoinbaseProgram generates the script for contorl coinbase output
-func CoinbaseProgram(pubkeys []ed25519.PublicKey, nrequired int, height uint64) ([]byte, error) {
+// DefaultCoinbaseProgram generates the script for contorl coinbase output
+func DefaultCoinbaseProgram() ([]byte, error) {
        builder := NewBuilder()
-       builder.AddOp(vm.OP_BLOCKHEIGHT)
-       builder.AddInt64(int64(height))
-       builder.AddOp(vm.OP_GREATERTHAN)
-       builder.AddOp(vm.OP_VERIFY)
-
-       if nrequired == 0 {
-               return builder.Build()
-       }
-       if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
-               return nil, err
-       }
+       builder.AddOp(vm.OP_TRUE)
        return builder.Build()
 }