mirror of https://github.com/poanetwork/quorum.git
210 lines
6.3 KiB
Go
210 lines
6.3 KiB
Go
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"html/template"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"os"
|
|
osExec "os/exec"
|
|
"path"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/private"
|
|
"github.com/ethereum/go-ethereum/private/constellation"
|
|
)
|
|
|
|
// callmsg is the message type used for call transactions in the private state test
|
|
type callmsg struct {
|
|
addr common.Address
|
|
to *common.Address
|
|
gas, gasPrice *big.Int
|
|
value *big.Int
|
|
data []byte
|
|
}
|
|
|
|
// accessor boilerplate to implement core.Message
|
|
func (m callmsg) From() common.Address { return m.addr }
|
|
func (m callmsg) FromFrontier() common.Address { return m.addr }
|
|
func (m callmsg) Nonce() uint64 { return 0 }
|
|
func (m callmsg) To() *common.Address { return m.to }
|
|
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
|
|
func (m callmsg) Gas() *big.Int { return m.gas }
|
|
func (m callmsg) Value() *big.Int { return m.value }
|
|
func (m callmsg) Data() []byte { return m.data }
|
|
func (m callmsg) CheckNonce() bool { return true }
|
|
|
|
func ExampleMakeCallHelper() {
|
|
var (
|
|
// setup new pair of keys for the calls
|
|
key, _ = crypto.GenerateKey()
|
|
// create a new helper
|
|
helper = MakeCallHelper()
|
|
)
|
|
// Private contract address
|
|
prvContractAddr := common.Address{1}
|
|
// Initialise custom code for private contract
|
|
helper.PrivateState.SetCode(prvContractAddr, common.Hex2Bytes("600a60005500"))
|
|
// Public contract address
|
|
pubContractAddr := common.Address{2}
|
|
// Initialise custom code for public contract
|
|
helper.PublicState.SetCode(pubContractAddr, common.Hex2Bytes("601460005500"))
|
|
|
|
// Make a call to the private contract
|
|
err := helper.MakeCall(true, key, prvContractAddr, nil)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
// Make a call to the public contract
|
|
err = helper.MakeCall(false, key, pubContractAddr, nil)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
|
|
// Output:
|
|
// Private: 10
|
|
// Public: 20
|
|
fmt.Println("Private:", helper.PrivateState.GetState(prvContractAddr, common.Hash{}).Big())
|
|
fmt.Println("Public:", helper.PublicState.GetState(pubContractAddr, common.Hash{}).Big())
|
|
}
|
|
|
|
var constellationCfgTemplate = template.Must(template.New("t").Parse(`
|
|
url = "http://127.0.0.1:9000/"
|
|
port = 9000
|
|
socketPath = "{{.RootDir}}/qdata/tm1.ipc"
|
|
otherNodeUrls = []
|
|
publicKeyPath = "{{.RootDir}}/keys/tm1.pub"
|
|
privateKeyPath = "{{.RootDir}}/keys/tm1.key"
|
|
archivalPublicKeyPath = "{{.RootDir}}/keys/tm1a.pub"
|
|
archivalPrivateKeyPath = "{{.RootDir}}/keys/tm1a.key"
|
|
storagePath = "{{.RootDir}}/qdata/constellation1"
|
|
`))
|
|
|
|
func runConstellation() (*osExec.Cmd, error) {
|
|
dir, err := ioutil.TempDir("", "TestPrivateTxConstellationData")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
here, err := os.Getwd()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = os.MkdirAll(path.Join(dir, "qdata"), 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
if err = os.Symlink(path.Join(here, "constellation-test-keys"), path.Join(dir, "keys")); err != nil {
|
|
return nil, err
|
|
}
|
|
cfgFile, err := os.Create(path.Join(dir, "constellation.cfg"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = constellationCfgTemplate.Execute(cfgFile, map[string]string{"RootDir": dir})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
constellationCmd := osExec.Command("constellation-node", cfgFile.Name())
|
|
var stdout, stderr bytes.Buffer
|
|
constellationCmd.Stdout = &stdout
|
|
constellationCmd.Stderr = &stderr
|
|
var constellationErr error
|
|
go func() {
|
|
constellationErr = constellationCmd.Start()
|
|
}()
|
|
// Give the constellation subprocess some time to start.
|
|
time.Sleep(1 * time.Second)
|
|
if constellationErr != nil {
|
|
fmt.Println(stdout.String() + stderr.String())
|
|
return nil, constellationErr
|
|
}
|
|
private.P = constellation.MustNew(cfgFile.Name())
|
|
return constellationCmd, nil
|
|
}
|
|
|
|
// 600a600055600060006001a1
|
|
// [1] PUSH1 0x0a (store value)
|
|
// [3] PUSH1 0x00 (store addr)
|
|
// [4] SSTORE
|
|
// [6] PUSH1 0x00
|
|
// [8] PUSH1 0x00
|
|
// [10] PUSH1 0x01
|
|
// [11] LOG1
|
|
//
|
|
// Store then log
|
|
func TestPrivateTransaction(t *testing.T) {
|
|
var (
|
|
key, _ = crypto.GenerateKey()
|
|
helper = MakeCallHelper()
|
|
privateState = helper.PrivateState
|
|
publicState = helper.PublicState
|
|
)
|
|
|
|
constellationCmd, err := runConstellation()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer constellationCmd.Process.Kill()
|
|
|
|
prvContractAddr := common.Address{1}
|
|
pubContractAddr := common.Address{2}
|
|
privateState.SetCode(prvContractAddr, common.Hex2Bytes("600a600055600060006001a1"))
|
|
privateState.SetState(prvContractAddr, common.Hash{}, common.Hash{9})
|
|
publicState.SetCode(pubContractAddr, common.Hex2Bytes("6014600055"))
|
|
publicState.SetState(pubContractAddr, common.Hash{}, common.Hash{19})
|
|
|
|
if publicState.Exist(prvContractAddr) {
|
|
t.Error("didn't expect private contract address to exist on public state")
|
|
}
|
|
|
|
// Private transaction 1
|
|
err = helper.MakeCall(true, key, prvContractAddr, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stateEntry := privateState.GetState(prvContractAddr, common.Hash{}).Big()
|
|
if stateEntry.Cmp(big.NewInt(10)) != 0 {
|
|
t.Error("expected state to have 10, got", stateEntry)
|
|
}
|
|
if len(privateState.Logs()) != 1 {
|
|
t.Error("expected private state to have 1 log, got", len(privateState.Logs()))
|
|
}
|
|
if len(publicState.Logs()) != 0 {
|
|
t.Error("expected public state to have 0 logs, got", len(publicState.Logs()))
|
|
}
|
|
if publicState.Exist(prvContractAddr) {
|
|
t.Error("didn't expect private contract address to exist on public state")
|
|
}
|
|
if !privateState.Exist(prvContractAddr) {
|
|
t.Error("expected private contract address to exist on private state")
|
|
}
|
|
|
|
// Public transaction 1
|
|
err = helper.MakeCall(false, key, pubContractAddr, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stateEntry = publicState.GetState(pubContractAddr, common.Hash{}).Big()
|
|
if stateEntry.Cmp(big.NewInt(20)) != 0 {
|
|
t.Error("expected state to have 20, got", stateEntry)
|
|
}
|
|
|
|
// Private transaction 2
|
|
err = helper.MakeCall(true, key, prvContractAddr, nil)
|
|
stateEntry = privateState.GetState(prvContractAddr, common.Hash{}).Big()
|
|
if stateEntry.Cmp(big.NewInt(10)) != 0 {
|
|
t.Error("expected state to have 10, got", stateEntry)
|
|
}
|
|
|
|
if publicState.Exist(prvContractAddr) {
|
|
t.Error("didn't expect private contract address to exist on public state")
|
|
}
|
|
if privateState.Exist(pubContractAddr) {
|
|
t.Error("didn't expect public contract address to exist on private state")
|
|
}
|
|
}
|