From e4b67d34431b96ad71de8d4665ed0c30f9c9a059 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Thu, 21 Mar 2019 10:55:16 +0100 Subject: [PATCH 1/7] Initial block creation tx --- types/transactions_blockcreation.go | 270 ++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 types/transactions_blockcreation.go diff --git a/types/transactions_blockcreation.go b/types/transactions_blockcreation.go new file mode 100644 index 000000000..a7bf2dc05 --- /dev/null +++ b/types/transactions_blockcreation.go @@ -0,0 +1,270 @@ +package types + +import ( + "encoding/json" + "errors" + "fmt" + "io" + + "github.com/threefoldtech/rivine/crypto" + "github.com/threefoldtech/rivine/pkg/encoding/rivbin" +) + +// These Specifiers are used internally when calculating a type's ID. See +// Specifier for more details. +var ( + SpecifierBlockCreationTransaction = Specifier{'b', 'l', 'o', 'c', 'k', ' ', 'c', 'r', 'e', 'a', 't', 'i', 'o', 'n'} +) + +const ( + // TransactionVersionBlockCreation defines the special transaction used for + // creating blocks by referencing an owned blockstake output + TransactionVersionBlockCreation TransactionVersion = 2 +) + +type ( + // BlockCreationTransaction defines the transaction (with version 0x02) + // used to create a new block by proving ownership of a referenced + // blockstake output + BlockCreationTransaction struct { + // Reference unlocks a blockstake output to prove ownership, but does not consume it + Reference BlockStakeInput + } + + // BlockCreationTransactionExtension defines the BlockCreationTransaction Extension Data + BlockCreationTransactionExtension struct { + // Reference unlocks a blockstake output to prove ownership, but does not consume it + Reference BlockStakeInput + } +) + +// BlockCreationTransactionFromTransaction creates a BlockCreationTransaction, using a regular in-memory rivine transaction +func BlockCreationTransactionFromTransaction(tx Transaction) (BlockCreationTransaction, error) { + if tx.Version != TransactionVersionBlockCreation { + return BlockCreationTransaction{}, fmt.Errorf( + "block creation transaction requires tx version %d", TransactionVersionBlockCreation, + ) + } + return BlockCreationTransactionFromTransactionData(TransactionData{ + CoinInputs: tx.CoinInputs, + CoinOutputs: tx.CoinOutputs, + BlockStakeInputs: tx.BlockStakeInputs, + BlockStakeOutputs: tx.BlockStakeOutputs, + MinerFees: tx.MinerFees, + ArbitraryData: tx.ArbitraryData, + Extension: tx.Extension, + }) +} + +// BlockCreationTransactionFromTransactionData creates an BlockCreationTransaction, +// using the TransactionData from a regular in-memory rivine transaction. +func BlockCreationTransactionFromTransactionData(txData TransactionData) (BlockCreationTransaction, error) { + // validate transaction data + + // no coin inputs or outputs allowed + if len(txData.CoinInputs) != 0 || len(txData.CoinOutputs) != 0 { + return BlockCreationTransaction{}, errors.New("no coin input or outputs allowed for a block creation transaction") + } + + // no miner fee allowed + if len(txData.MinerFees) != 0 { + return BlockCreationTransaction{}, errors.New("no transaction fees allowed for a block creation transaction") + } + + // no arb data allowed + if len(txData.ArbitraryData) != 0 { + return BlockCreationTransaction{}, errors.New("no arbitrary data allowed for a block creation transaction") + } + + // no blockstake input and outputs allowed, can't move block stakes + if len(txData.BlockStakeOutputs) != 0 || len(txData.BlockStakeInputs) != 0 { + return BlockCreationTransaction{}, errors.New("no blockstake outputs allowed for a block creation transaction") + } + + extensionData, ok := txData.Extension.(*BlockCreationTransactionExtension) + if !ok { + return BlockCreationTransaction{}, errors.New("invalid extension data for a block creation transaction") + } + + tx := BlockCreationTransaction{ + Reference: extensionData.Reference, + } + + return tx, nil +} + +// TransactionData returns this BlockCreationTransaction +// as regular rivine transaction data. +func (bctx *BlockCreationTransaction) TransactionData() TransactionData { + txData := TransactionData{ + Extension: &BlockCreationTransactionExtension{ + Reference: bctx.Reference, + }, + } + return txData +} + +// Transaction returns this BlockCreationTransaction +// as regular rivine transaction, using TransactionVersionBlockCreation as the type. +func (bctx *BlockCreationTransaction) Transaction() Transaction { + tx := Transaction{ + Version: TransactionVersionBlockCreation, + Extension: &BlockCreationTransactionExtension{ + Reference: bctx.Reference, + }, + } + return tx +} + +// MarshalSia implements SiaMarshaler.MarshalSia, +// alias of MarshalRivine for backwards-compatibility reasons. +func (bctx BlockCreationTransaction) MarshalSia(w io.Writer) error { + return bctx.MarshalRivine(w) +} + +// UnmarshalSia implements SiaUnmarshaler.UnmarshalSia, +// alias of UnmarshalRivine for backwards-compatibility reasons. +func (bctx *BlockCreationTransaction) UnmarshalSia(r io.Reader) error { + return bctx.UnmarshalRivine(r) +} + +// MarshalRivine implements RivineMarshaler.MarshalRivine +func (bctx BlockCreationTransaction) MarshalRivine(w io.Writer) error { + return rivbin.NewEncoder(w).EncodeAll( + bctx.Reference, + ) +} + +// UnmarshalRivine implements RivineUnmarshaler.UnmarshalRivine +func (bctx *BlockCreationTransaction) UnmarshalRivine(r io.Reader) error { + return rivbin.NewDecoder(r).DecodeAll( + &bctx.Reference, + ) +} + +type ( + // BlockCreationTransactionController defines a transaction controller for a a transaction type + // reserved at type 0x02. It allows creation of blocks without blockstake respend + BlockCreationTransactionController struct{} +) + +var ( + // ensure at compile time that BlockCreationTransactionController + // implements the desired interfaces + _ TransactionController = BlockCreationTransactionController{} + _ TransactionValidator = BlockCreationTransactionController{} + _ CoinOutputValidator = BlockCreationTransactionController{} + _ BlockStakeOutputValidator = BlockCreationTransactionController{} + _ TransactionSignatureHasher = BlockCreationTransactionController{} + _ TransactionIDEncoder = BlockCreationTransactionController{} +) + +// EncodeTransactionData implements TransactionController.EncodeTransactionData +func (bctc BlockCreationTransactionController) EncodeTransactionData(w io.Writer, txData TransactionData) error { + bctx, err := BlockCreationTransactionFromTransactionData(txData) + if err != nil { + return fmt.Errorf("failed to convert txData to a BlockCreationTx: %v", err) + } + return rivbin.NewEncoder(w).Encode(bctx) +} + +// DecodeTransactionData implements TransactionController.DecodeTransactionData +func (bctc BlockCreationTransactionController) DecodeTransactionData(r io.Reader) (TransactionData, error) { + var bctx BlockCreationTransaction + err := rivbin.NewDecoder(r).Decode(&bctx) + if err != nil { + return TransactionData{}, fmt.Errorf( + "failed to binary-decode tx as a BlockCreationTx: %v", err) + } + // return block creation tx as regular rivine tx data + return bctx.TransactionData(), nil +} + +// JSONEncodeTransactionData implements TransactionController.JSONEncodeTransactionData +func (bctc BlockCreationTransactionController) JSONEncodeTransactionData(txData TransactionData) ([]byte, error) { + bctx, err := BlockCreationTransactionFromTransactionData(txData) + if err != nil { + return nil, fmt.Errorf("failed to convert txData to a BlockCreationTx: %v", err) + } + return json.Marshal(bctx) +} + +// JSONDecodeTransactionData implements TransactionController.JSONDecodeTransactionData +func (bctc BlockCreationTransactionController) JSONDecodeTransactionData(data []byte) (TransactionData, error) { + var bctx BlockCreationTransaction + err := json.Unmarshal(data, &bctx) + if err != nil { + return TransactionData{}, fmt.Errorf( + "failed to json-decode tx as a BlockCreationTx:: %v", err) + } + // return block creation tx as regular rivine tx data + return bctx.TransactionData(), nil +} + +// ValidateTransaction implements TransactionValidator.ValidateTransaction +func (bctc BlockCreationTransactionController) ValidateTransaction(t Transaction, ctx ValidationContext, constants TransactionValidationConstants) error { + // check tx fits within a block + err := TransactionFitsInABlock(t, constants.BlockSizeLimit) + if err != nil { + return err + } + + // get BlockCreationTx + bctx, err := BlockCreationTransactionFromTransaction(t) + if err != nil { + return fmt.Errorf("failed to use tx as a BlockCreationTx: %v", err) + } + + // check if the reference is a standard fulfillment + if err = bctx.Reference.Fulfillment.IsStandardFulfillment(ctx); err != nil { + return err + } + + // Tx is valid + return nil +} + +// ValidateCoinOutputs implements CoinOutputValidator.ValidateCoinOutputs, +func (bctc BlockCreationTransactionController) ValidateCoinOutputs(t Transaction, ctx FundValidationContext, coinInputs map[CoinOutputID]CoinOutput) error { + // no coin input and outputs + return nil +} + +// ValidateBlockStakeOutputs implements BlockStakeOutputValidator.ValidateBlockStakeOutputs +func (bctc BlockCreationTransactionController) ValidateBlockStakeOutputs(t Transaction, ctx FundValidationContext, blockStakeInputs map[BlockStakeOutputID]BlockStakeOutput) (err error) { + return nil // always valid, no block stake inputs/outputs +} + +// SignatureHash implements TransactionSignatureHasher.SignatureHash +func (bctc BlockCreationTransactionController) SignatureHash(t Transaction, extraObjects ...interface{}) (crypto.Hash, error) { + bctx, err := BlockCreationTransactionFromTransaction(t) + if err != nil { + return crypto.Hash{}, fmt.Errorf("failed to use tx as a BlockCreationTx: %v", err) + } + + h := crypto.NewHash() + enc := rivbin.NewEncoder(h) + + enc.EncodeAll( + t.Version, + SpecifierBlockCreationTransaction, + bctx.Reference.ParentID, + ) + + if len(extraObjects) > 0 { + enc.EncodeAll(extraObjects...) + } + + var hash crypto.Hash + h.Sum(hash[:0]) + return hash, nil +} + +// EncodeTransactionIDInput implements TransactionIDEncoder.EncodeTransactionIDInput +func (bctc BlockCreationTransactionController) EncodeTransactionIDInput(w io.Writer, txData TransactionData) error { + bctx, err := BlockCreationTransactionFromTransactionData(txData) + if err != nil { + return fmt.Errorf("failed to convert txData to a BlockCreationTx: %v", err) + } + return rivbin.NewEncoder(w).EncodeAll(SpecifierBlockCreationTransaction, bctx) +} From 1f9b606700c2e6cde4475622b922b8004393f99b Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Wed, 27 Mar 2019 10:23:01 +0100 Subject: [PATCH 2/7] Remove unused interfaces from blockcreate tx --- types/transactions_blockcreation.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/types/transactions_blockcreation.go b/types/transactions_blockcreation.go index a7bf2dc05..d4230ad27 100644 --- a/types/transactions_blockcreation.go +++ b/types/transactions_blockcreation.go @@ -153,8 +153,6 @@ var ( // implements the desired interfaces _ TransactionController = BlockCreationTransactionController{} _ TransactionValidator = BlockCreationTransactionController{} - _ CoinOutputValidator = BlockCreationTransactionController{} - _ BlockStakeOutputValidator = BlockCreationTransactionController{} _ TransactionSignatureHasher = BlockCreationTransactionController{} _ TransactionIDEncoder = BlockCreationTransactionController{} ) @@ -224,17 +222,6 @@ func (bctc BlockCreationTransactionController) ValidateTransaction(t Transaction return nil } -// ValidateCoinOutputs implements CoinOutputValidator.ValidateCoinOutputs, -func (bctc BlockCreationTransactionController) ValidateCoinOutputs(t Transaction, ctx FundValidationContext, coinInputs map[CoinOutputID]CoinOutput) error { - // no coin input and outputs - return nil -} - -// ValidateBlockStakeOutputs implements BlockStakeOutputValidator.ValidateBlockStakeOutputs -func (bctc BlockCreationTransactionController) ValidateBlockStakeOutputs(t Transaction, ctx FundValidationContext, blockStakeInputs map[BlockStakeOutputID]BlockStakeOutput) (err error) { - return nil // always valid, no block stake inputs/outputs -} - // SignatureHash implements TransactionSignatureHasher.SignatureHash func (bctc BlockCreationTransactionController) SignatureHash(t Transaction, extraObjects ...interface{}) (crypto.Hash, error) { bctx, err := BlockCreationTransactionFromTransaction(t) From c5770435346ce50630f51562d3d69d9d67800956 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Fri, 29 Mar 2019 12:05:12 +0100 Subject: [PATCH 3/7] Sign blockcreate tx in blockcreator --- cmd/rivined/daemon.go | 2 + modules/blockcreator/proofofblockstake.go | 56 ++++++++++++++++++----- modules/wallet.go | 7 +++ modules/wallet/transactionbuilder.go | 5 ++ types/transactions_blockcreation.go | 49 +++++++++++++++++--- 5 files changed, 101 insertions(+), 18 deletions(-) diff --git a/cmd/rivined/daemon.go b/cmd/rivined/daemon.go index b35aace20..986b09d7d 100644 --- a/cmd/rivined/daemon.go +++ b/cmd/rivined/daemon.go @@ -18,6 +18,7 @@ import ( "github.com/threefoldtech/rivine/modules/wallet" "github.com/threefoldtech/rivine/pkg/api" "github.com/threefoldtech/rivine/pkg/daemon" + "github.com/threefoldtech/rivine/types" ) func runDaemon(cfg daemon.Config, networkCfg daemon.NetworkConfig, moduleIdentifiers daemon.ModuleIdentifierSet) error { @@ -85,6 +86,7 @@ func runDaemon(cfg daemon.Config, networkCfg daemon.NetworkConfig, moduleIdentif fmt.Println("Error during consensus set shutdown:", err) } }() + types.RegisterTransactionVersion(types.TransactionVersionBlockCreation, types.NewBlockCreationTransactionController(cs)) } var tpool modules.TransactionPool diff --git a/modules/blockcreator/proofofblockstake.go b/modules/blockcreator/proofofblockstake.go index 998e501dd..53ba1bcfd 100644 --- a/modules/blockcreator/proofofblockstake.go +++ b/modules/blockcreator/proofofblockstake.go @@ -2,6 +2,7 @@ package blockcreator import ( "encoding/json" + "errors" "math/big" "time" @@ -157,24 +158,57 @@ func (bc *BlockCreator) RespentBlockStake(ubso types.UnspentBlockStakeOutput) er } } - //otherwise the blockstake is not yet spent in this block, spent it now - t := bc.wallet.StartTransaction() - err := t.SpendBlockStake(ubso.BlockStakeOutputID) // link the input of this transaction - // to the used BlockStake output + bso, err := bc.cs.GetBlockStakeOutput(ubso.BlockStakeOutputID) if err != nil { return err } - bso := types.BlockStakeOutput{ - Value: ubso.Value, //use the same amount of BlockStake - Condition: ubso.Condition, //use the same condition. + if bso.Condition.ConditionType() != types.ConditionTypeUnlockHash { + return errors.New("unsupported output condition for pobs") } - t.AddBlockStakeOutput(bso) - txnSet, err := t.Sign() + + pk, _, err := bc.wallet.GetKey(bso.Condition.UnlockHash()) if err != nil { + return errors.New("Failed to retrieve public key for blockstake output") + } + + // create the input for the used output + input := types.BlockStakeInput{ParentID: ubso.BlockStakeOutputID, Fulfillment: types.NewFulfillment(types.NewSingleSignatureFulfillment(pk))} + + // create the extension for the block creation tx based on the used input + txExt := &types.BlockCreationTransactionExtension{Reference: input} + + // Create transactionbuilder for the new transaction and add the extension + txb := bc.wallet.StartTransactionWithVersion(types.TransactionVersionBlockCreation) + txb.SetExtension(txExt) + if err = txb.SignAllPossible(); err != nil { return err } - //add this transaction in front of the list of unsolved block transactions - bc.unsolvedBlock.Transactions = append(txnSet, bc.unsolvedBlock.Transactions...) + + tx, _ := txb.View() + + // //otherwise the blockstake is not yet spent in this block, spent it now + // t := bc.wallet.StartTransaction() + // err = t.SpendBlockStake(ubso.BlockStakeOutputID) // link the input of this transaction + // // to the used BlockStake output + // if err != nil { + // return err + // } + + // bso := types.BlockStakeOutput{ + // Value: ubso.Value, //use the same amount of BlockStake + // Condition: ubso.Condition, //use the same condition. + // } + // t.AddBlockStakeOutput(bso) + // txnSet, err := t.Sign() + // if err != nil { + // return err + // } + // //add this transaction in front of the list of unsolved block transactions + // bc.unsolvedBlock.Transactions = append(txnSet, bc.unsolvedBlock.Transactions...) + + // add this transaction in front of the list of unsolved block transactions + bc.unsolvedBlock.Transactions = append([]types.Transaction{tx}, bc.unsolvedBlock.Transactions...) + return nil } diff --git a/modules/wallet.go b/modules/wallet.go index f120a4a8e..047cc4e8c 100644 --- a/modules/wallet.go +++ b/modules/wallet.go @@ -192,6 +192,9 @@ type ( // AddArbitraryData sets the arbitrary data of the transaction. SetArbitraryData(arb []byte) + // SetExtension sets the extension of the transaction + SetExtension(interface{}) + // Sign will sign any inputs added by 'FundCoins' or 'FundBlockStakes' // and return a transaction set that contains all parents prepended to // the transaction. If more fields need to be added, a new transaction @@ -389,6 +392,10 @@ type ( // RegisterTransaction(types.Transaction{}, nil) StartTransaction() TransactionBuilder + // StartTransactionWithVersion is a convenience function that calls + // RegisterTransaction(types.Transaction{Version: version}, nil). + StartTransactionWithVersion(types.TransactionVersion) TransactionBuilder + // SendCoins is a tool for sending coins from the wallet to anyone who can fulfill the // given condition (can be nil). The transaction is automatically given to the transaction pool, and // are also returned to the caller. diff --git a/modules/wallet/transactionbuilder.go b/modules/wallet/transactionbuilder.go index 511ceff92..1e8ef3b53 100644 --- a/modules/wallet/transactionbuilder.go +++ b/modules/wallet/transactionbuilder.go @@ -354,6 +354,11 @@ func (tb *transactionBuilder) SetArbitraryData(arb []byte) { tb.transaction.ArbitraryData = arb } +// SetExtension sets the extension of the transaction +func (tb *transactionBuilder) SetExtension(extension interface{}) { + tb.transaction.Extension = extension +} + // Drop discards all of the outputs in a transaction, returning them to the // pool so that other transactions may use them. 'Drop' should only be called // if a transaction is both unsigned and will not be used any further. diff --git a/types/transactions_blockcreation.go b/types/transactions_blockcreation.go index d4230ad27..b230d8c2a 100644 --- a/types/transactions_blockcreation.go +++ b/types/transactions_blockcreation.go @@ -81,13 +81,15 @@ func BlockCreationTransactionFromTransactionData(txData TransactionData) (BlockC return BlockCreationTransaction{}, errors.New("no blockstake outputs allowed for a block creation transaction") } - extensionData, ok := txData.Extension.(*BlockCreationTransactionExtension) - if !ok { - return BlockCreationTransaction{}, errors.New("invalid extension data for a block creation transaction") - } + tx := BlockCreationTransaction{} + + if txData.Extension != nil { + extensionData, ok := txData.Extension.(*BlockCreationTransactionExtension) + if !ok { + return tx, errors.New("invalid extension data for a block creation transaction") + } - tx := BlockCreationTransaction{ - Reference: extensionData.Reference, + tx.Reference = extensionData.Reference } return tx, nil @@ -145,7 +147,14 @@ func (bctx *BlockCreationTransaction) UnmarshalRivine(r io.Reader) error { type ( // BlockCreationTransactionController defines a transaction controller for a a transaction type // reserved at type 0x02. It allows creation of blocks without blockstake respend - BlockCreationTransactionController struct{} + BlockCreationTransactionController struct { + bsog BlockStakeOutputGetter + } + + //BlockStakeOutputGetter allows the retrieval of a blockstake output based on its ID + BlockStakeOutputGetter interface { + GetBlockStakeOutput(BlockStakeOutputID) (BlockStakeOutput, error) + } ) var ( @@ -155,8 +164,16 @@ var ( _ TransactionValidator = BlockCreationTransactionController{} _ TransactionSignatureHasher = BlockCreationTransactionController{} _ TransactionIDEncoder = BlockCreationTransactionController{} + _ TransactionExtensionSigner = BlockCreationTransactionController{} ) +// NewBlockCreationTransactionController creates a new block creation transaction controller +func NewBlockCreationTransactionController(bsog BlockStakeOutputGetter) BlockCreationTransactionController { + return BlockCreationTransactionController{ + bsog: bsog, + } +} + // EncodeTransactionData implements TransactionController.EncodeTransactionData func (bctc BlockCreationTransactionController) EncodeTransactionData(w io.Writer, txData TransactionData) error { bctx, err := BlockCreationTransactionFromTransactionData(txData) @@ -255,3 +272,21 @@ func (bctc BlockCreationTransactionController) EncodeTransactionIDInput(w io.Wri } return rivbin.NewEncoder(w).EncodeAll(SpecifierBlockCreationTransaction, bctx) } + +// SignExtension implements TransactionExtensionSigner.SignExtension +func (bctc BlockCreationTransactionController) SignExtension(extension interface{}, sign func(*UnlockFulfillmentProxy, UnlockConditionProxy, ...interface{}) error) (interface{}, error) { + bctxExtension, ok := extension.(*BlockCreationTransactionExtension) + if !ok { + return nil, errors.New("Invalid extension data for a block creation transaction") + } + + bso, err := bctc.bsog.GetBlockStakeOutput(bctxExtension.Reference.ParentID) + if err != nil { + return nil, fmt.Errorf("failed to get the active mint condition: %v", err) + } + err = sign(&bctxExtension.Reference.Fulfillment, bso.Condition) + if err != nil { + return nil, fmt.Errorf("failed to sign block creation tx extension: %v", err) + } + return bctxExtension, nil +} From 91890d20b30ecac6be3fadfee56fa5d911f2f942 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Mon, 1 Apr 2019 10:36:03 +0200 Subject: [PATCH 4/7] Support block creation tx in pobs validation --- modules/consensus/block_validation.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/modules/consensus/block_validation.go b/modules/consensus/block_validation.go index ea06ac0ed..23e69db11 100644 --- a/modules/consensus/block_validation.go +++ b/modules/consensus/block_validation.go @@ -107,6 +107,17 @@ func (bv stdBlockValidator) ValidateBlock(b types.Block, minTimestamp types.Time spent = true } } + // check block creation txes, as they don't technically respend + if tr.Version == types.TransactionVersionBlockCreation { + ext, ok := tr.Extension.(*types.BlockCreationTransactionExtension) + if !ok { + // should never happen + continue + } + if ext.Reference.ParentID == bsoid { + spent = true + } + } } } } @@ -123,6 +134,18 @@ func (bv stdBlockValidator) ValidateBlock(b types.Block, minTimestamp types.Time spent = true } } + // check block creation txes, as they don't technically respend + if tr.Version == types.TransactionVersionBlockCreation { + ext, ok := tr.Extension.(*types.BlockCreationTransactionExtension) + if !ok { + // should never happen + continue + } + if ext.Reference.ParentID == blockatheight.Transactions[ubsu.TransactionIndex].BlockStakeOutputID(ubsu.OutputIndex) { + bv.cs.log.Debugf("[SBV] Confirmed blockstake respend from an inactive fork, ubsu in block %d, new block at height %d\n", ubsu.BlockHeight, height) + spent = true + } + } } } } From d6fa892b11061d58066959c1a6394868e0e3a875 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Mon, 1 Apr 2019 16:09:38 +0200 Subject: [PATCH 5/7] Add height to block creation tx --- modules/blockcreator/proofofblockstake.go | 6 +++++- types/transactions_blockcreation.go | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/blockcreator/proofofblockstake.go b/modules/blockcreator/proofofblockstake.go index 53ba1bcfd..1c8999bfc 100644 --- a/modules/blockcreator/proofofblockstake.go +++ b/modules/blockcreator/proofofblockstake.go @@ -158,6 +158,10 @@ func (bc *BlockCreator) RespentBlockStake(ubso types.UnspentBlockStakeOutput) er } } + // get current height so we can store the block height of the block the tx is + // supposed to make in the block (currentHeight + 1) + currentHeight := bc.cs.Height() + bso, err := bc.cs.GetBlockStakeOutput(ubso.BlockStakeOutputID) if err != nil { return err @@ -176,7 +180,7 @@ func (bc *BlockCreator) RespentBlockStake(ubso types.UnspentBlockStakeOutput) er input := types.BlockStakeInput{ParentID: ubso.BlockStakeOutputID, Fulfillment: types.NewFulfillment(types.NewSingleSignatureFulfillment(pk))} // create the extension for the block creation tx based on the used input - txExt := &types.BlockCreationTransactionExtension{Reference: input} + txExt := &types.BlockCreationTransactionExtension{Reference: input, Height: types.BlockHeight(currentHeight + 1)} // Create transactionbuilder for the new transaction and add the extension txb := bc.wallet.StartTransactionWithVersion(types.TransactionVersionBlockCreation) diff --git a/types/transactions_blockcreation.go b/types/transactions_blockcreation.go index b230d8c2a..ddcd9ad13 100644 --- a/types/transactions_blockcreation.go +++ b/types/transactions_blockcreation.go @@ -29,12 +29,16 @@ type ( BlockCreationTransaction struct { // Reference unlocks a blockstake output to prove ownership, but does not consume it Reference BlockStakeInput + // Height for the block this tx is going to create + Height BlockHeight } // BlockCreationTransactionExtension defines the BlockCreationTransaction Extension Data BlockCreationTransactionExtension struct { // Reference unlocks a blockstake output to prove ownership, but does not consume it Reference BlockStakeInput + // Height for the block this tx is going to create + Height BlockHeight } ) @@ -90,6 +94,7 @@ func BlockCreationTransactionFromTransactionData(txData TransactionData) (BlockC } tx.Reference = extensionData.Reference + tx.Height = extensionData.Height } return tx, nil @@ -101,6 +106,7 @@ func (bctx *BlockCreationTransaction) TransactionData() TransactionData { txData := TransactionData{ Extension: &BlockCreationTransactionExtension{ Reference: bctx.Reference, + Height: bctx.Height, }, } return txData @@ -113,6 +119,7 @@ func (bctx *BlockCreationTransaction) Transaction() Transaction { Version: TransactionVersionBlockCreation, Extension: &BlockCreationTransactionExtension{ Reference: bctx.Reference, + Height: bctx.Height, }, } return tx @@ -235,6 +242,11 @@ func (bctc BlockCreationTransactionController) ValidateTransaction(t Transaction return err } + // check block height in tx + if bctx.Height != ctx.BlockHeight { + return fmt.Errorf("tx is supposed to create block %v, but is in block %v", bctx.Height, ctx.BlockHeight) + } + // Tx is valid return nil } @@ -253,6 +265,7 @@ func (bctc BlockCreationTransactionController) SignatureHash(t Transaction, extr t.Version, SpecifierBlockCreationTransaction, bctx.Reference.ParentID, + bctx.Height, ) if len(extraObjects) > 0 { From 0b511679567fa9c6cdf7480c3a2fee76b1e59987 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Mon, 1 Apr 2019 17:07:36 +0200 Subject: [PATCH 6/7] Signature validation for block creation transactions --- types/transactions_blockcreation.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/types/transactions_blockcreation.go b/types/transactions_blockcreation.go index ddcd9ad13..86b811cb6 100644 --- a/types/transactions_blockcreation.go +++ b/types/transactions_blockcreation.go @@ -242,6 +242,15 @@ func (bctc BlockCreationTransactionController) ValidateTransaction(t Transaction return err } + bso, err := bctc.bsog.GetBlockStakeOutput(bctx.Reference.ParentID) + if err != nil { + return fmt.Errorf("failed to get the referenced blockstake output condition condition: %v", err) + } + + if err = bso.Condition.Fulfill(bctx.Reference.Fulfillment, FulfillContext{BlockHeight: ctx.BlockHeight, BlockTime: ctx.BlockTime, Transaction: t, ExtraObjects: nil}); err != nil { + return err + } + // check block height in tx if bctx.Height != ctx.BlockHeight { return fmt.Errorf("tx is supposed to create block %v, but is in block %v", bctx.Height, ctx.BlockHeight) @@ -295,7 +304,7 @@ func (bctc BlockCreationTransactionController) SignExtension(extension interface bso, err := bctc.bsog.GetBlockStakeOutput(bctxExtension.Reference.ParentID) if err != nil { - return nil, fmt.Errorf("failed to get the active mint condition: %v", err) + return nil, fmt.Errorf("failed to get the referenced blockstake output condition condition: %v", err) } err = sign(&bctxExtension.Reference.Fulfillment, bso.Condition) if err != nil { From 36ead2b04aed522b33125c88ecd08f6d68453965 Mon Sep 17 00:00:00 2001 From: LeeSmet Date: Wed, 3 Apr 2019 11:17:45 +0200 Subject: [PATCH 7/7] Remove old block creation code --- modules/blockcreator/proofofblockstake.go | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/modules/blockcreator/proofofblockstake.go b/modules/blockcreator/proofofblockstake.go index 1c8999bfc..e86e53038 100644 --- a/modules/blockcreator/proofofblockstake.go +++ b/modules/blockcreator/proofofblockstake.go @@ -158,6 +158,8 @@ func (bc *BlockCreator) RespentBlockStake(ubso types.UnspentBlockStakeOutput) er } } + // No valid blockstake have been spend yet in the block to be created + // get current height so we can store the block height of the block the tx is // supposed to make in the block (currentHeight + 1) currentHeight := bc.cs.Height() @@ -191,26 +193,6 @@ func (bc *BlockCreator) RespentBlockStake(ubso types.UnspentBlockStakeOutput) er tx, _ := txb.View() - // //otherwise the blockstake is not yet spent in this block, spent it now - // t := bc.wallet.StartTransaction() - // err = t.SpendBlockStake(ubso.BlockStakeOutputID) // link the input of this transaction - // // to the used BlockStake output - // if err != nil { - // return err - // } - - // bso := types.BlockStakeOutput{ - // Value: ubso.Value, //use the same amount of BlockStake - // Condition: ubso.Condition, //use the same condition. - // } - // t.AddBlockStakeOutput(bso) - // txnSet, err := t.Sign() - // if err != nil { - // return err - // } - // //add this transaction in front of the list of unsolved block transactions - // bc.unsolvedBlock.Transactions = append(txnSet, bc.unsolvedBlock.Transactions...) - // add this transaction in front of the list of unsolved block transactions bc.unsolvedBlock.Transactions = append([]types.Transaction{tx}, bc.unsolvedBlock.Transactions...)