quorum/core/private_state_test.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")
}
}