Skip to content

Commit

Permalink
feat(dpos2.0): use VM to check standard or multi signature transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
RainFallsSilent committed Jul 22, 2022
1 parent 5b71022 commit 6f77387
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 73 deletions.
2 changes: 1 addition & 1 deletion blockchain/txvalidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ func checkTransactionSignature(tx interfaces.Transaction, references map[*common
// sort the program hashes of owner and programs of the transaction
common.SortProgramHashByCodeHash(programHashes)
SortPrograms(tx.Programs())
return RunPrograms(buf.Bytes(), programHashes, tx.Programs())
return RunPrograms(tx, buf.Bytes(), programHashes, tx.Programs())
}

func CheckAmountPrecise(amount common.Fixed64, precision byte) bool {
Expand Down
95 changes: 42 additions & 53 deletions blockchain/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var GetDataContainer = func(programHash *common.Uint168, tx interfaces.Transacti
return tx
}

func RunProgramsVM(tx interfaces.Transaction, hashes []common.Uint168, programs []*Program) error {
func RunPrograms(tx interfaces.Transaction, data []byte, hashes []common.Uint168, programs []*Program) error {
if tx == nil {
return errors.New("invalid data content nil transaction")
}
Expand All @@ -34,46 +34,16 @@ func RunProgramsVM(tx interfaces.Transaction, hashes []common.Uint168, programs
}

for i := 0; i < len(programs); i++ {
codeHash := common.ToCodeHash(programs[i].Code)
program := programs[i]
programHash := hashes[i]

if !hashes[i].ToCodeHash().IsEqual(*codeHash) {
return errors.New("data hash is different from corresponding program code")
}
//execute program on VM
se := vm.NewExecutionEngine(GetDataContainer(&hashes[i], tx),
new(vm.CryptoECDsa), vm.MAXSTEPS, nil, nil)
se.LoadScript(programs[i].Code, false)
se.LoadScript(programs[i].Parameter, true)
se.Execute()

if se.GetState() != vm.HALT {
return errors.New("[VM] Finish State not equal to HALT")
}

if se.GetEvaluationStack().Count() != 1 {
return errors.New("[VM] Execute Engine Stack Count Error")
}

success := se.GetExecuteResult()
if !success {
return errors.New("[VM] Check Sig FALSE")
}
}

return nil
}

func RunPrograms(data []byte, programHashes []common.Uint168, programs []*Program) error {
if len(programHashes) != len(programs) {
return errors.New("the number of data hashes is different with number of programs")
}
codeHash := common.ToCodeHash(program.Code)

for i, program := range programs {
programHash := programHashes[i]
prefixType := contract.GetPrefixType(programHash)

// TODO: this implementation will be deprecated
if prefixType == contract.PrefixCrossChain {

switch prefixType {
case contract.PrefixCrossChain:
if contract.IsSchnorr(program.Code) {
if ok, err := checkSchnorrSignatures(*program, common.Sha256D(data[:])); !ok {
return errors.New("check schnorr signature failed:" + err.Error())
Expand All @@ -84,32 +54,51 @@ func RunPrograms(data []byte, programHashes []common.Uint168, programs []*Progra
}
}
continue
}

codeHash := common.ToCodeHash(program.Code)
ownerHash := programHash.ToCodeHash()

if !ownerHash.IsEqual(*codeHash) {
return errors.New("the data hashes is different with corresponding program code")
}
case contract.PrefixStandard, contract.PrefixDeposit:
if !hashes[i].ToCodeHash().IsEqual(*codeHash) {
return errors.New("data hash is different from corresponding program code")
}

if prefixType == contract.PrefixStandard || prefixType == contract.PrefixDeposit {
if contract.IsSchnorr(program.Code) {
if ok, err := checkSchnorrSignatures(*program, common.Sha256D(data[:])); !ok {
return errors.New("check schnorr signature failed:" + err.Error())
}
} else {
if err := CheckStandardSignature(*program, data); err != nil {
return err
}
continue
}
} else if prefixType == contract.PrefixMultiSig {
if err := CheckMultiSigSignatures(*program, data); err != nil {
return err

case contract.PrefixMultiSig:
if !hashes[i].ToCodeHash().IsEqual(*codeHash) {
return errors.New("data hash is different from corresponding program code")
}
} else {
//if err := CheckMultiSigSignatures(*program, data); err != nil {
// return err
//}

default:
return errors.New("unknown signature type")
}

// check standard or multi signature
// execute program on VM
se := vm.NewExecutionEngine(GetDataContainer(&hashes[i], tx),
new(vm.CryptoECDsa), vm.MAXSTEPS, nil, nil)
se.LoadScript(programs[i].Code, false)
se.LoadScript(programs[i].Parameter, true)
se.Execute()

if se.GetState() != vm.HALT {
return errors.New("[VM] Finish State not equal to HALT")
}

if se.GetEvaluationStack().Count() != 1 {
return errors.New("[VM] Execute Engine Stack Count Error")
}

success := se.GetExecuteResult()
if !success {
return errors.New("[VM] Check Sig FALSE")
}
}

return nil
Expand Down
10 changes: 2 additions & 8 deletions core/transaction/transactionchecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,14 +594,8 @@ func checkTransactionSignature(tx interfaces.Transaction, references map[*common
// sort the program hashes of owner and programs of the transaction
common.SortProgramHashByCodeHash(programHashes)
blockchain.SortPrograms(tx.Programs())
return blockchain.RunPrograms(buf.Bytes(), programHashes, tx.Programs())

// todo complete me
//
//switch tx.TxType() {
//case common2.TxType
//}
//return blockchain.RunProgramsVM(tx, programHashes, tx.Programs())

return blockchain.RunPrograms(tx, buf.Bytes(), programHashes, tx.Programs())
}

func checkTransactionDepositOutputs(bc *blockchain.BlockChain, txn interfaces.Transaction) error {
Expand Down
22 changes: 11 additions & 11 deletions test/unit/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func TestSchnorrRunProgramsOrigin(t *testing.T) {
programHash := c.ToProgramHash()
hashes = append(hashes, *programHash)
programs = append(programs, &program.Program{Code: redeemscript, Parameter: sig[:]})
err = blockchain.RunPrograms(data, hashes[0:1], programs)
err = blockchain.RunPrograms(tx, data, hashes[0:1], programs)
assert.NoError(t, err, "[RunProgram] passed with 1 checksig program")

})
Expand Down Expand Up @@ -566,7 +566,7 @@ func TestSchnorrRunPrograms(t *testing.T) {
init(schnorrAccountNum)

for index := 0; index < schnorrAccountNum; index++ {
err = blockchain.RunPrograms(data, hashes[index:index+1], programs[index:index+1])
err = blockchain.RunPrograms(tx, data, hashes[index:index+1], programs[index:index+1])
if err != nil {
fmt.Printf("AggregateSignatures index %d fail err %s \n", index, err.Error())
} else {
Expand Down Expand Up @@ -618,7 +618,7 @@ func TestRunPrograms(t *testing.T) {
break
}
}
err = blockchain.RunPrograms(data, hashes[index:index+1], programs[index:index+1])
err = blockchain.RunPrograms(tx, data, hashes[index:index+1], programs[index:index+1])
assert.NoError(t, err, "[RunProgram] passed with 1 checksig program")

// 1 loop multisig
Expand All @@ -629,25 +629,25 @@ func TestRunPrograms(t *testing.T) {
break
}
}
err = blockchain.RunPrograms(data, hashes[index:index+1], programs[index:index+1])
err = blockchain.RunPrograms(tx, data, hashes[index:index+1], programs[index:index+1])
assert.NoError(t, err, "[RunProgram] passed with 1 multisig program")

// multiple programs
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.NoError(t, err, "[RunProgram] passed with multiple programs")

// hashes count not equal to programs count
init()
removeIndex := math.Intn(num)
hashes = append(hashes[:removeIndex], hashes[removeIndex+1:]...)
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with unmathed hashes")
assert.Equal(t, "the number of data hashes is different with number of programs", err.Error())

// With no programs
init()
programs = []*program.Program{}
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with no programs")
assert.Equal(t, "the number of data hashes is different with number of programs", err.Error())

Expand All @@ -656,15 +656,15 @@ func TestRunPrograms(t *testing.T) {
for i := 0; i < num; i++ {
rand.Read(hashes[math.Intn(num)][:])
}
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with unmathed hashes")
assert.Equal(t, "the data hashes is different with corresponding program code", err.Error())

// With disordered hashes
init()
common.SortProgramHashByCodeHash(hashes)
sort.Sort(sort.Reverse(blockchain.ByHash(programs)))
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with disordered hashes")
assert.Equal(t, "the data hashes is different with corresponding program code", err.Error())

Expand All @@ -673,7 +673,7 @@ func TestRunPrograms(t *testing.T) {
for i := 0; i < num; i++ {
programs[math.Intn(num)].Code = nil
}
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with random no code")
assert.Equal(t, "the data hashes is different with corresponding program code", err.Error())

Expand All @@ -683,7 +683,7 @@ func TestRunPrograms(t *testing.T) {
index := math.Intn(num)
programs[index].Parameter = nil
}
err = blockchain.RunPrograms(data, hashes, programs)
err = blockchain.RunPrograms(tx, data, hashes, programs)
assert.Error(t, err, "[RunProgram] passed with random no parameter")
}

Expand Down

0 comments on commit 6f77387

Please sign in to comment.