--- /dev/null
+package bcrp
+
+import (
+ "bytes"
+
+ "github.com/bytom/bytom/consensus"
+ "github.com/bytom/bytom/errors"
+ "github.com/bytom/bytom/protocol/vm"
+)
+
+//bcrp bytom contract register protocol
+const bcrp = "bcrp"
+
+// IsBCRPScript checks if a control program is bytom contract register protocol
+// BCRP script format: OP_FAIL + OP_PUSHDATA1 + "04" + hex("bcrp") + OP_PUSHDATA1 + "01" + "01" + OP_PUSHDATA1 + len(contract) + contract
+func IsBCRPScript(prog []byte) bool {
+ inst, err := vm.ParseProgram(prog)
+ if err != nil {
+ return false
+ }
+
+ if len(inst) != 4 {
+ return false
+ }
+
+ if inst[0].Op != vm.OP_FAIL {
+ return false
+ }
+
+ if inst[1].Op != vm.OP_PUSHDATA1 {
+ return false
+ }
+
+ if !bytes.Equal(inst[1].Data, []byte(bcrp)) {
+ return false
+ }
+
+ if inst[2].Op != vm.OP_PUSHDATA1 {
+ return false
+ }
+
+ // version 1
+ if !bytes.Equal(inst[2].Data, []byte{byte(1)}) {
+ return false
+ }
+
+ if inst[3].Op != vm.OP_PUSHDATA1 {
+ return false
+ }
+
+ return true
+}
+
+// IsCallBCRPScript checks if a control program is call contract registered by bytom contract register protocol
+// call BCRP script format: OP_1 + OP_DATA_32 + SHA3-256(contract)
+func IsCallBCRPScript(prog []byte) bool {
+ insts, err := vm.ParseProgram(prog)
+ if err != nil {
+ return false
+ }
+
+ if len(insts) != 2 {
+ return false
+ }
+
+ if insts[0].Op != vm.OP_1 {
+ return false
+ }
+
+ return insts[1].Op == vm.OP_DATA_32 && len(insts[1].Data) == consensus.BCRPContractHashDataSize
+}
+
+// ParseContractHash parse contract hash from call BCRP script
+// call BCRP script format: OP_1 + OP_DATA_32 + SHA3-256(contract)
+func ParseContractHash(prog []byte) ([32]byte, error) {
+ insts, err := vm.ParseProgram(prog)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ if len(insts) != 2 {
+ return [32]byte{}, errors.New("unsupport program")
+ }
+
+ var hash [32]byte
+ copy(hash[:], insts[1].Data)
+
+ return hash, nil
+}
--- /dev/null
+package bcrp
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+func TestIsBCRPScript(t *testing.T) {
+ tests := []struct {
+ program string
+ expected bool
+ }{
+ {
+ program: "",
+ expected: false,
+ },
+ {
+ program: "ae20ac20f5cdb9ada2ae9836bcfff32126d6b885aa3f73ee111a95d1bf37f3904aca5151ad",
+ expected: false,
+ },
+ {
+ program: "694c04626372704c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
+ expected: false,
+ },
+ {
+ program: "6a4c04424352504c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
+ expected: false,
+ },
+ {
+ program: "6a4c04626372704c01024c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
+ expected: false,
+ },
+ {
+ program: "6a4c04626372704c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
+ expected: true,
+ },
+ }
+
+ for i, test := range tests {
+ program, err := hex.DecodeString(test.program)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := IsBCRPScript(program)
+ if expected != test.expected {
+ t.Errorf("TestIsTemplateRegister #%d failed: got %v want %v", i, expected, test.expected)
+ }
+ }
+}
+
+func TestIsCallBCRPScript(t *testing.T) {
+ tests := []struct {
+ program string
+ expected bool
+ }{
+ {
+ program: "",
+ expected: false,
+ },
+ {
+ program: "6a4c04626372704c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
+ expected: false,
+ },
+ {
+ program: "00204e4f02d43bf50171f7f25d046b7f016002da410fc00d2e8902e7b170c98cf946",
+ expected: false,
+ },
+ {
+ program: "514c204e4f02d43bf50171f7f25d046b7f016002da410fc00d2e8902e7b170c98cf946",
+ expected: false,
+ },
+ {
+ program: "51204e4f02d43bf50171f7f25d046b7f016002da410fc00d2e8902e7b170c98cf946",
+ expected: true,
+ },
+ }
+
+ for i, test := range tests {
+ program, err := hex.DecodeString(test.program)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := IsCallBCRPScript(program)
+ if expected != test.expected {
+ t.Errorf("TestIsCallBCRPScript #%d failed: got %v want %v", i, expected, test.expected)
+ }
+ }
+}
+
PayToWitnessPubKeyHashDataSize = 20
PayToWitnessScriptHashDataSize = 32
+ BCRPContractHashDataSize = 32
CoinbaseArbitrarySizeLimit = 128
BTMAlias = "BTM"
package segwit
import (
- "bytes"
"errors"
"github.com/bytom/bytom/consensus"
"github.com/bytom/bytom/protocol/vm/vmutil"
)
-//bcrp bytom contract register protocol
-const bcrp = "bcrp"
-
func IsP2WScript(prog []byte) bool {
return IsP2WPKHScript(prog) || IsP2WSHScript(prog) || IsStraightforward(prog)
}
return insts[1].Op == vm.OP_DATA_32 && len(insts[1].Data) == consensus.PayToWitnessScriptHashDataSize
}
-// IsBCRPScript checks if a control program is bytom contract register protocol
-// BCRP script format: OP_FAIL + OP_PUSHDATA1 + "04" + hex("bcrp") + OP_PUSHDATA1 + "01" + "01" + OP_PUSHDATA1 + len(contract) + contract
-func IsBCRPScript(prog []byte) bool {
- inst, err := vm.ParseProgram(prog)
- if err != nil {
- return false
- }
-
- if len(inst) != 4 {
- return false
- }
-
- if inst[0].Op != vm.OP_FAIL {
- return false
- }
-
- if inst[1].Op != vm.OP_PUSHDATA1 {
- return false
- }
-
- if !bytes.Equal(inst[1].Data, []byte(bcrp)) {
- return false
- }
-
- if inst[2].Op != vm.OP_PUSHDATA1 {
- return false
- }
-
- // version 1
- if !bytes.Equal(inst[2].Data, []byte{byte(1)}) {
- return false
- }
-
- if inst[3].Op != vm.OP_PUSHDATA1 {
- return false
- }
-
- return true
-}
-
func ConvertP2PKHSigProgram(prog []byte) ([]byte, error) {
insts, err := vm.ParseProgram(prog)
if err != nil {
t.Errorf("case #%d (%s) got %t, expect %t", i, c.desc, c.fun(progBytes), c.yes)
}
}
-}
-
-func TestIsBCRPScript(t *testing.T) {
- tests := []struct {
- program string
- expected bool
- }{
- {
- program: "",
- expected: false,
- },
- {
- program: "ae20ac20f5cdb9ada2ae9836bcfff32126d6b885aa3f73ee111a95d1bf37f3904aca5151ad",
- expected: false,
- },
- {
- program: "694c04626372704c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
- expected: false,
- },
- {
- program: "6a4c04424352504c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
- expected: false,
- },
- {
- program: "6a4c04626372704c01024c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
- expected: false,
- },
- {
- program: "6a4c04626372704c01014c2820e9108d3ca8049800727f6a3505b3a2710dc579405dde03c250f16d9a7e1e6e787403ae7cac00c0",
- expected: true,
- },
- }
-
- for i, test := range tests {
- program, err := hex.DecodeString(test.program)
- if err != nil {
- t.Fatal(err)
- }
-
- expected := IsBCRPScript(program)
- if expected != test.expected {
- t.Errorf("TestIsTemplateRegister #%d failed: got %v want %v", i, expected, test.expected)
- }
- }
-}
+}
\ No newline at end of file
"bytes"
dbm "github.com/bytom/bytom/database/leveldb"
+ "github.com/bytom/bytom/errors"
"github.com/bytom/bytom/protocol/state"
)
}
return nil
}
+
+func getContract(db dbm.DB, hash [32]byte) ([]byte, error) {
+ data := db.Get(CalcContractKey(hash))
+ if data == nil {
+ return nil, errors.New("can't find the registered contract by contract hash")
+ }
+
+ // data:"txID+program.Code" len(txID) == 32
+ if len(data) <= 32 {
+ return nil, errors.New("registered contract format error")
+ }
+
+ return data[32:], nil
+}
return getUtxo(s.db, hash)
}
+func (s *Store) GetContract(hash [32]byte) ([]byte, error) {
+ return getContract(s.db, hash)
+}
+
// BlockExist check if the block is stored in disk
func (s *Store) BlockExist(hash *bc.Hash) bool {
block, err := s.cache.lookup(hash)
bcBlock := types.MapBlock(block)
parent := c.index.GetNode(&block.PreviousBlockHash)
- if err := validation.ValidateBlock(bcBlock, parent); err != nil {
+ if err := validation.ValidateBlock(bcBlock, parent, c.ProgramConverter); err != nil {
return errors.Sub(ErrBadBlock, err)
}
package state
import (
- "github.com/bytom/bytom/consensus/segwit"
+ "github.com/bytom/bytom/consensus/bcrp"
"github.com/bytom/bytom/crypto/sha3pool"
"github.com/bytom/bytom/protocol/bc/types"
)
for _, tx := range block.Transactions {
for _, output := range tx.Outputs {
program := output.ControlProgram
- if !segwit.IsBCRPScript(program) {
+ if !bcrp.IsBCRPScript(program) {
continue
}
var hash [32]byte
for _, tx := range block.Transactions {
for _, output := range tx.Outputs {
program := output.ControlProgram
- if !segwit.IsBCRPScript(program) {
+ if !bcrp.IsBCRPScript(program) {
continue
}
var hash [32]byte
GetStoreStatus() *BlockStoreState
GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error
GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)
+ GetContract(hash [32]byte) ([]byte, error)
GetCheckpoint(*bc.Hash) (*state.Checkpoint, error)
GetCheckpointsByHeight(uint64) ([]*state.Checkpoint, error)
import (
log "github.com/sirupsen/logrus"
+ "github.com/bytom/bytom/consensus/bcrp"
"github.com/bytom/bytom/errors"
"github.com/bytom/bytom/protocol/bc"
"github.com/bytom/bytom/protocol/bc/types"
}
bh := c.BestBlockHeader()
- gasStatus, err := validation.ValidateTx(tx.Tx, types.MapBlock(&types.Block{BlockHeader: *bh}))
+ gasStatus, err := validation.ValidateTx(tx.Tx, types.MapBlock(&types.Block{BlockHeader: *bh}), c.ProgramConverter)
if err != nil {
log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("transaction status fail")
c.txPool.AddErrCache(&tx.ID, err)
return c.txPool.ProcessTransaction(tx, bh.Height, gasStatus.BTMValue)
}
+
+//ProgramConverter convert program. Only for BCRP now
+func (c *Chain) ProgramConverter(prog []byte) ([]byte, error) {
+ hash, err := bcrp.ParseContractHash(prog)
+ if err != nil {
+ return nil, err
+ }
+
+ return c.store.GetContract(hash)
+}
func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
+func (s *mockStore) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
func (s *mockStore) SaveBlock(*types.Block) error { return nil }
func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint) error {
return nil
}
func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
+func (s *mockStore1) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
func (s *mockStore1) SaveBlock(*types.Block) error { return nil }
func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint) error { return nil}
}
// ValidateBlock validates a block and the transactions within.
-func ValidateBlock(b *bc.Block, parent *state.BlockNode) error {
+func ValidateBlock(b *bc.Block, parent *state.BlockNode, converter ProgramConverterFunc) error {
startTime := time.Now()
if err := ValidateBlockHeader(b, parent); err != nil {
return err
blockGasSum := uint64(0)
coinbaseAmount := consensus.BlockSubsidy(b.BlockHeader.Height)
- validateResults := ValidateTxs(b.Transactions, b)
+ validateResults := ValidateTxs(b.Transactions, b, converter)
for i, validateResult := range validateResults {
if validateResult.err != nil {
return errors.Wrapf(validateResult.err, "validate of transaction %d of %d, gas_valid:%v", i, len(b.Transactions), validateResult.gasStatus.GasValid)
// TestValidateBlock test the ValidateBlock function
func TestValidateBlock(t *testing.T) {
cp, _ := vmutil.DefaultCoinbaseProgram()
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
cases := []struct {
desc string
block *bc.Block
}
for i, c := range cases {
- err := ValidateBlock(c.block, c.parent)
+ err := ValidateBlock(c.block, c.parent, converter)
if rootErr(err) != c.err {
t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
}
// TestGasOverBlockLimit check if the gas of the block has the max limit (blocktest#1012)
func TestGasOverBlockLimit(t *testing.T) {
-
cp, _ := vmutil.DefaultCoinbaseProgram()
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
parent := &state.BlockNode{
Version: 1,
Height: 0,
}))
}
- if err := ValidateBlock(block, parent); err != errOverBlockLimit {
+ if err := ValidateBlock(block, parent, converter); err != errOverBlockLimit {
t.Errorf("got error %s, want %s", err, errOverBlockLimit)
}
}
tx := types.NewTx(c.txData)
mockSignTx(tx, c.insts)
bcTx := types.MapTx(&c.txData)
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
_, err := validation.ValidateTx(bcTx, &bc.Block{
BlockHeader: &bc.BlockHeader{Height: 1},
Transactions: []*bc.Tx{bcTx},
- })
+ }, converter)
if !c.err && err != nil {
t.Errorf("case #%d (%s) expect no error, got error %s", i, c.desc, err)
}
return nil
}
+// ProgramConverterFunc represent a func convert control program
+type ProgramConverterFunc func(prog []byte) ([]byte, error)
+
// validationState contains the context that must propagate through
// the transaction graph when validating entries.
type validationState struct {
block *bc.Block
tx *bc.Tx
gasStatus *GasState
- entryID bc.Hash // The ID of the nearest enclosing entry
- sourcePos uint64 // The source position, for validate ValueSources
- destPos uint64 // The destination position, for validate ValueDestinations
- cache map[bc.Hash]error // Memoized per-entry validation results
+ entryID bc.Hash // The ID of the nearest enclosing entry
+ sourcePos uint64 // The source position, for validate ValueSources
+ destPos uint64 // The destination position, for validate ValueDestinations
+ cache map[bc.Hash]error // Memoized per-entry validation results
+ converter ProgramConverterFunc // Program converter function
}
func checkValid(vs *validationState, e bc.Entry) (err error) {
}
// ValidateTx validates a transaction.
-func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) {
+func ValidateTx(tx *bc.Tx, block *bc.Block, converter ProgramConverterFunc) (*GasState, error) {
if block.Version == 1 && tx.Version != 1 {
return &GasState{GasValid: false}, errors.WithDetailf(ErrTxVersion, "block version %d, transaction version %d", block.Version, tx.Version)
}
entryID: tx.ID,
gasStatus: &GasState{GasValid: false},
cache: make(map[bc.Hash]error),
+ converter: converter,
}
if err := checkValid(vs, tx.TxHeader); err != nil {
return r.err
}
-func validateTxWorker(workCh chan *validateTxWork, resultCh chan *ValidateTxResult, wg *sync.WaitGroup) {
+func validateTxWorker(workCh chan *validateTxWork, resultCh chan *ValidateTxResult, wg *sync.WaitGroup, converter ProgramConverterFunc) {
for work := range workCh {
- gasStatus, err := ValidateTx(work.tx, work.block)
+ gasStatus, err := ValidateTx(work.tx, work.block, converter)
resultCh <- &ValidateTxResult{i: work.i, gasStatus: gasStatus, err: err}
}
wg.Done()
}
// ValidateTxs validates txs in async mode
-func ValidateTxs(txs []*bc.Tx, block *bc.Block) []*ValidateTxResult {
+func ValidateTxs(txs []*bc.Tx, block *bc.Block, converter ProgramConverterFunc) []*ValidateTxResult {
txSize := len(txs)
validateWorkerNum := runtime.NumCPU()
//init the goroutine validate worker
resultCh := make(chan *ValidateTxResult, txSize)
for i := 0; i <= validateWorkerNum && i < txSize; i++ {
wg.Add(1)
- go validateTxWorker(workCh, resultCh, &wg)
+ go validateTxWorker(workCh, resultCh, &wg, converter)
}
//sent the works
)
func TestValidateTx(t *testing.T) {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
cases := []struct {
desc string
txData *types.TxData
}
for i, c := range cases {
- gasStatus, err := ValidateTx(types.MapTx(c.txData), mockBlock())
+ gasStatus, err := ValidateTx(types.MapTx(c.txData), mockBlock(), converter)
if rootErr(err) != c.err {
t.Errorf("case #%d (%s) got error %s, want %s; validationState is:\n", i, c.desc, err, c.err)
}
func TestOverflow(t *testing.T) {
sourceID := &bc.Hash{V0: 9999}
ctrlProgram := []byte{byte(vm.OP_TRUE)}
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
newTx := func(inputs []uint64, outputs []uint64) *bc.Tx {
txInputs := make([]*types.TxInput, 0, len(inputs))
txOutputs := make([]*types.TxOutput, 0, len(outputs))
for i, c := range cases {
tx := newTx(c.inputs, c.outputs)
- if _, err := ValidateTx(tx, mockBlock()); rootErr(err) != c.err {
+ if _, err := ValidateTx(tx, mockBlock(), converter); rootErr(err) != c.err {
t.Fatalf("case %d test failed, want %s, have %s", i, c.err, rootErr(err))
}
}
func TestCoinbase(t *testing.T) {
cp, _ := vmutil.DefaultCoinbaseProgram()
retire, _ := vmutil.RetireProgram([]byte{})
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
CbTx := types.MapTx(&types.TxData{
SerializedSize: 1,
Inputs: []*types.TxInput{
}
for i, c := range cases {
- gasStatus, err := ValidateTx(c.block.Transactions[c.txIndex], c.block)
+ gasStatus, err := ValidateTx(c.block.Transactions[c.txIndex], c.block, converter)
if rootErr(err) != c.err {
t.Errorf("#%d got error %s, want %s", i, err, c.err)
func TestRuleAA(t *testing.T) {
testData := "070100040161015f9bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e01011600147c7662d92bd5e77454736f94731c60a6e9cbc69f6302404a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004200530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce9940160015ee334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace6842001011600147c7662d92bd5e77454736f94731c60a6e9cbc69f6302404a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004200530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce9940161015f9bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e01011600147c7662d92bd5e77454736f94731c60a6e9cbc69f63024062c29b20941e7f762c3afae232f61d8dac1c544825931e391408c6715c408ef69f494a1b3b61ce380ddee0c8b18ecac2b46ef96a62eebb6ec40f9f545410870a200530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce9940160015ee334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace6842001011600147c7662d92bd5e77454736f94731c60a6e9cbc69f630240e443d66c75b4d5fa71676d60b0b067e6941f06349f31e5f73a7d51a73f5797632b2e01e8584cd1c8730dc16df075866b0c796bd7870182e2da4b37188208fe02200530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce9940201003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08ba3fae80e01160014aac0345165045e612b3d7363f39a372bead80ce70001003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08fe0fae80e01160014aac0345165045e612b3d7363f39a372bead80ce700"
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
tx := types.Tx{}
if err := tx.UnmarshalText([]byte(testData)); err != nil {
t.Errorf("fail on unmarshal txData: %s", err)
}
for i, c := range cases {
- _, err := ValidateTx(tx.Tx, c.block)
+ _, err := ValidateTx(tx.Tx, c.block, converter)
if rootErr(err) != c.err {
t.Errorf("#%d got error %s, want %s", i, err, c.err)
}
// TestTimeRange test the checkTimeRange function (txtest#1004)
func TestTimeRange(t *testing.T) {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
cases := []struct {
timeRange uint64
err bool
for i, c := range cases {
tx.TimeRange = c.timeRange
- if _, err := ValidateTx(tx, block); (err != nil) != c.err {
+ if _, err := ValidateTx(tx, block, converter); (err != nil) != c.err {
t.Errorf("#%d got error %t, want %t", i, !c.err, c.err)
}
}
}
func TestValidateTxVersion(t *testing.T) {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
cases := []struct {
desc string
block *bc.Block
}
for i, c := range cases {
- if _, err := ValidateTx(c.block.Transactions[0], c.block); rootErr(err) != c.err {
+ if _, err := ValidateTx(c.block.Transactions[0], c.block, converter); rootErr(err) != c.err {
t.Errorf("case #%d (%s) got error %t, want %t", i, c.desc, err, c.err)
}
}
import (
"bytes"
+ "github.com/bytom/bytom/consensus/bcrp"
"github.com/bytom/bytom/consensus/segwit"
"github.com/bytom/bytom/crypto/sha3pool"
"github.com/bytom/bytom/errors"
result := &vm.Context{
VMVersion: prog.VmVersion,
- Code: witnessProgram(prog.Code),
+ Code: convertProgram(prog.Code, vs.converter),
Arguments: args,
EntryID: entryID.Bytes(),
return result
}
-func witnessProgram(prog []byte) []byte {
+func convertProgram(prog []byte, converter ProgramConverterFunc) []byte {
if segwit.IsP2WPKHScript(prog) {
if witnessProg, err := segwit.ConvertP2PKHSigProgram([]byte(prog)); err == nil {
return witnessProg
if witnessProg, err := segwit.ConvertP2SHProgram([]byte(prog)); err == nil {
return witnessProg
}
+ } else if bcrp.IsCallBCRPScript(prog) {
+ if contractProg, err := converter(prog); err == nil {
+ return contractProg
+ }
}
return prog
}
bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: preBlockHeader.Height + 1}}
for _, tx := range txs {
- gasStatus, err := validation.ValidateTx(tx.Tx, bcBlock)
+ gasStatus, err := validation.ValidateTx(tx.Tx, bcBlock, chain.ProgramConverter)
if err != nil {
continue
}
"github.com/bytom/bytom/blockchain/pseudohsm"
"github.com/bytom/bytom/blockchain/signers"
"github.com/bytom/bytom/crypto/ed25519/chainkd"
+ dbm "github.com/bytom/bytom/database/leveldb"
"github.com/bytom/bytom/protocol/bc/types"
"github.com/bytom/bytom/protocol/validation"
"github.com/bytom/bytom/test"
- dbm "github.com/bytom/bytom/database/leveldb"
)
func TestP2PKH(t *testing.T) {
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}
}
tx.SerializedSize = 1
- if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock()); err != nil {
+ converter := func(prog []byte) ([]byte, error) { return nil, nil }
+ if _, err = validation.ValidateTx(types.MapTx(tx), test.MockBlock(), converter); err != nil {
t.Fatal(err)
}
}