core: implement witness verification logic

Fix #368.
This commit is contained in:
Roman Khimov 2019-09-23 20:13:44 +03:00
parent ca9c9be71f
commit 679e01bd0f
2 changed files with 39 additions and 17 deletions

View file

@ -1,6 +1,7 @@
package core package core
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"math" "math"
@ -12,6 +13,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -902,28 +904,35 @@ func (bc *Blockchain) VerifyWitnesses(t *transaction.Transaction) error {
verification := witnesses[i].VerificationScript verification := witnesses[i].VerificationScript
if len(verification) == 0 { if len(verification) == 0 {
/*TODO: replicate following C# code: bb := new(bytes.Buffer)
using (ScriptBuilder sb = new ScriptBuilder()) err = vm.EmitAppCall(bb, hashes[i], false)
{ if err != nil {
sb.EmitAppCall(hashes[i].ToArray()); return err
verification = sb.ToArray();
} }
*/ verification = bb.Bytes()
} else { } else {
if h := witnesses[i].ScriptHash(); hashes[i] != h { if h := witnesses[i].ScriptHash(); hashes[i] != h {
return errors.Errorf("hash mismatch for script #%d", i) return errors.Errorf("hash mismatch for script #%d", i)
} }
} }
/*TODO: replicate following C# code: vm := vm.New(vm.ModeMute)
using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, Fixed8.Zero)) vm.SetCheckedHash(t.VerificationHash().Bytes())
{ vm.LoadScript(verification)
engine.LoadScript(verification); vm.LoadScript(witnesses[i].InvocationScript)
engine.LoadScript(verifiable.Witnesses[i].InvocationScript); vm.Run()
if (!engine.Execute()) return false; if vm.HasFailed() {
if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; return errors.Errorf("vm failed to execute the script")
}*/ }
res := vm.PopResult()
switch res.(type) {
case bool:
if !(res.(bool)) {
return errors.Errorf("signature check failed")
}
default:
return errors.Errorf("vm returned non-boolean result")
}
} }
return nil return nil

View file

@ -39,9 +39,12 @@ type Transaction struct {
// and invocation script. // and invocation script.
Scripts []*Witness `json:"scripts"` Scripts []*Witness `json:"scripts"`
// hash of the transaction // Hash of the transaction (double SHA256).
hash util.Uint256 hash util.Uint256
// Hash of the transaction used to verify it (single SHA256).
verificationHash util.Uint256
// Trimmed indicates this is a transaction from trimmed // Trimmed indicates this is a transaction from trimmed
// data. // data.
Trimmed bool `json:"-"` Trimmed bool `json:"-"`
@ -64,6 +67,14 @@ func (t *Transaction) Hash() util.Uint256 {
return t.hash return t.hash
} }
// VerificationHash returns the hash of the transaction used to verify it.
func (t *Transaction) VerificationHash() util.Uint256 {
if t.verificationHash.Equals(util.Uint256{}) {
t.createHash()
}
return t.verificationHash
}
// AddOutput adds the given output to the transaction outputs. // AddOutput adds the given output to the transaction outputs.
func (t *Transaction) AddOutput(out *Output) { func (t *Transaction) AddOutput(out *Output) {
t.Outputs = append(t.Outputs, out) t.Outputs = append(t.Outputs, out)
@ -196,7 +207,9 @@ func (t *Transaction) createHash() error {
return buf.Err return buf.Err
} }
t.hash = hash.DoubleSha256(buf.Bytes()) b := buf.Bytes()
t.hash = hash.DoubleSha256(b)
t.verificationHash = hash.Sha256(b)
return nil return nil
} }