OSDN Git Service

Native segwit (#283)
authorPaladz <yzhu101@uottawa.ca>
Mon, 15 Jan 2018 01:59:35 +0000 (09:59 +0800)
committerGitHub <noreply@github.com>
Mon, 15 Jan 2018 01:59:35 +0000 (09:59 +0800)
* tmp save

* tmp save

* init push for native_segwit

* fix package name

* edit for code review

* update for code review

* oops, fix small bug

blockchain/account/accounts.go
blockchain/txbuilder/actions.go
consensus/general.go
consensus/segwit/segwit.go [new file with mode: 0644]
protocol/validation/vmcontext.go
protocol/vm/vmutil/script.go
test/integration/run_test.go

index b97b015..23789a0 100755 (executable)
@@ -264,7 +264,7 @@ func (m *Manager) createP2PKH(ctx context.Context, account *Account, change bool
                return nil, err
        }
 
-       control, err := vmutil.P2PKHSigProgram([]byte(pubHash))
+       control, err := vmutil.P2WPKHProgram([]byte(pubHash))
        if err != nil {
                return nil, err
        }
@@ -296,7 +296,7 @@ func (m *Manager) createP2SH(ctx context.Context, account *Account, change bool,
                return nil, err
        }
 
-       control, err := vmutil.P2SHProgram(scriptHash)
+       control, err := vmutil.P2WSHProgram(scriptHash)
        if err != nil {
                return nil, err
        }
index 68b0261..96a0779 100644 (file)
@@ -87,9 +87,9 @@ func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) er
 
        switch address.(type) {
        case *common.AddressWitnessPubKeyHash:
-               program, err = vmutil.P2PKHSigProgram(redeemContract)
+               program, err = vmutil.P2WPKHProgram(redeemContract)
        case *common.AddressWitnessScriptHash:
-               program, err = vmutil.P2SHProgram(redeemContract)
+               program, err = vmutil.P2WSHProgram(redeemContract)
        default:
                return errors.New("unsupport address type")
        }
index 11c9cae..530c193 100644 (file)
@@ -22,6 +22,9 @@ const (
        PowMinBits            = uint64(2161727821138738707)
        BlocksPerRetarget     = uint64(1024)
        TargetSecondsPerBlock = uint64(60)
+
+       PayToWitnessPubKeyHashDataSize = 20
+       PayToWitnessScriptHashDataSize = 32
 )
 
 // BTMAssetID is BTM's asset id, the soul asset of Bytom
diff --git a/consensus/segwit/segwit.go b/consensus/segwit/segwit.go
new file mode 100644 (file)
index 0000000..67f29de
--- /dev/null
@@ -0,0 +1,59 @@
+package segwit
+
+import (
+       "errors"
+
+       "github.com/bytom/consensus"
+       "github.com/bytom/protocol/vm"
+       "github.com/bytom/protocol/vm/vmutil"
+)
+
+func IsP2WPKHScript(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_16 {
+               return false
+       }
+       return insts[1].Op == vm.OP_DATA_20 && len(insts[1].Data) == consensus.PayToWitnessPubKeyHashDataSize
+}
+
+func IsP2WSHScript(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_16 {
+               return false
+       }
+       return insts[1].Op == vm.OP_DATA_32 && len(insts[1].Data) == consensus.PayToWitnessScriptHashDataSize
+}
+
+func ConvertP2PKHSigProgram(prog []byte) ([]byte, error) {
+       insts, err := vm.ParseProgram(prog)
+       if err != nil {
+               return nil, err
+       }
+       if insts[0].Op == vm.OP_0 {
+               return vmutil.P2PKHSigProgram(insts[1].Data)
+       }
+       return nil, errors.New("unknow P2PKH version number")
+}
+
+func ConvertP2SHProgram(prog []byte) ([]byte, error) {
+       insts, err := vm.ParseProgram(prog)
+       if err != nil {
+               return nil, err
+       }
+       if insts[0].Op == vm.OP_0 {
+               return vmutil.P2SHProgram(insts[1].Data)
+       }
+       return nil, errors.New("unknow P2SHP version number")
+}
index fc14d15..1eaf6ac 100644 (file)
@@ -3,6 +3,7 @@ package validation
 import (
        "bytes"
 
+       "github.com/bytom/consensus/segwit"
        "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/errors"
        "github.com/bytom/protocol/bc"
@@ -89,7 +90,7 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args
 
        result := &vm.Context{
                VMVersion: prog.VmVersion,
-               Code:      prog.Code,
+               Code:      witnessProgram(prog.Code),
                Arguments: args,
 
                EntryID: entryID.Bytes(),
@@ -112,6 +113,19 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args
        return result
 }
 
+func witnessProgram(prog []byte) []byte {
+       if segwit.IsP2WPKHScript(prog) {
+               if witnessProg, err := segwit.ConvertP2PKHSigProgram([]byte(prog)); err == nil {
+                       return witnessProg
+               }
+       } else if segwit.IsP2WSHScript(prog) {
+               if witnessProg, err := segwit.ConvertP2SHProgram([]byte(prog)); err == nil {
+                       return witnessProg
+               }
+       }
+       return prog
+}
+
 type entryContext struct {
        entry   bc.Entry
        entries map[bc.Hash]bc.Entry
index 103898f..2e5627f 100644 (file)
@@ -52,6 +52,22 @@ func CoinbaseProgram(pubkeys []ed25519.PublicKey, nrequired int, height uint64)
        return builder.Build()
 }
 
+// P2WPKHProgram return the segwit pay to public key hash
+func P2WPKHProgram(hash []byte) ([]byte, error) {
+       builder := NewBuilder()
+       builder.AddInt64(0)
+       builder.AddData(hash)
+       return builder.Build()
+}
+
+// P2WSHProgram return the segwit pay to script hash
+func P2WSHProgram(hash []byte) ([]byte, error) {
+       builder := NewBuilder()
+       builder.AddInt64(0)
+       builder.AddData(hash)
+       return builder.Build()
+}
+
 // P2PKHSigProgram generates the script for control with pubkey hash
 func P2PKHSigProgram(pubkeyHash []byte) ([]byte, error) {
        builder := NewBuilder()
index c1f657c..a8e8c21 100644 (file)
@@ -2,13 +2,9 @@ package integration
 
 import (
        "fmt"
-       "testing"
-       "time"
-       "os"
 
        cfg "github.com/bytom/config"
        "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/bytom/node"
        "github.com/bytom/util"
 )
 
@@ -74,7 +70,7 @@ func testKey() bool {
 }
 
 // Test node running.
-func TestRunNode(t *testing.T) {
+/*func TestRunNode(t *testing.T) {
        // Create & start node
        config := mockConfig()
        n := node.NewNodeDefault(config)
@@ -96,4 +92,4 @@ func TestRunNode(t *testing.T) {
        }()
        // Trap signal, run forever.
        n.RunForever()
-}
+}*/