github.com/zjj1991/quorum@v0.0.0-20190524123704-ae4b0a1e1a19/core/private_state_test.go (about) 1 package core 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "html/template" 8 "io/ioutil" 9 "math/big" 10 "net" 11 "net/http" 12 "os" 13 osExec "os/exec" 14 "path" 15 "path/filepath" 16 "strings" 17 "testing" 18 "time" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/crypto" 22 "github.com/ethereum/go-ethereum/private" 23 "github.com/ethereum/go-ethereum/private/constellation" 24 ) 25 26 // callmsg is the message type used for call transactions in the private state test 27 type callmsg struct { 28 addr common.Address 29 to *common.Address 30 gas uint64 31 gasPrice *big.Int 32 value *big.Int 33 data []byte 34 } 35 36 // accessor boilerplate to implement core.Message 37 func (m callmsg) From() common.Address { return m.addr } 38 func (m callmsg) FromFrontier() common.Address { return m.addr } 39 func (m callmsg) Nonce() uint64 { return 0 } 40 func (m callmsg) To() *common.Address { return m.to } 41 func (m callmsg) GasPrice() *big.Int { return m.gasPrice } 42 func (m callmsg) Gas() uint64 { return m.gas } 43 func (m callmsg) Value() *big.Int { return m.value } 44 func (m callmsg) Data() []byte { return m.data } 45 func (m callmsg) CheckNonce() bool { return true } 46 47 func ExampleMakeCallHelper() { 48 var ( 49 // setup new pair of keys for the calls 50 key, _ = crypto.GenerateKey() 51 // create a new helper 52 helper = MakeCallHelper() 53 ) 54 // Private contract address 55 prvContractAddr := common.Address{1} 56 // Initialise custom code for private contract 57 helper.PrivateState.SetCode(prvContractAddr, common.Hex2Bytes("600a60005500")) 58 // Public contract address 59 pubContractAddr := common.Address{2} 60 // Initialise custom code for public contract 61 helper.PublicState.SetCode(pubContractAddr, common.Hex2Bytes("601460005500")) 62 63 // Make a call to the private contract 64 err := helper.MakeCall(true, key, prvContractAddr, nil) 65 if err != nil { 66 fmt.Println(err) 67 } 68 // Make a call to the public contract 69 err = helper.MakeCall(false, key, pubContractAddr, nil) 70 if err != nil { 71 fmt.Println(err) 72 } 73 74 // Output: 75 // Private: 10 76 // Public: 20 77 fmt.Println("Private:", helper.PrivateState.GetState(prvContractAddr, common.Hash{}).Big()) 78 fmt.Println("Public:", helper.PublicState.GetState(pubContractAddr, common.Hash{}).Big()) 79 } 80 81 var constellationCfgTemplate = template.Must(template.New("t").Parse(` 82 url = "http://127.0.0.1:9000/" 83 port = 9000 84 socketPath = "{{.RootDir}}/qdata/tm1.ipc" 85 otherNodeUrls = [] 86 publicKeyPath = "{{.RootDir}}/keys/tm1.pub" 87 privateKeyPath = "{{.RootDir}}/keys/tm1.key" 88 archivalPublicKeyPath = "{{.RootDir}}/keys/tm1a.pub" 89 archivalPrivateKeyPath = "{{.RootDir}}/keys/tm1a.key" 90 storagePath = "{{.RootDir}}/qdata/constellation1" 91 `)) 92 93 func runConstellation() (*osExec.Cmd, error) { 94 dir, err := ioutil.TempDir("", "TestPrivateTxConstellationData") 95 if err != nil { 96 return nil, err 97 } 98 defer os.RemoveAll(dir) 99 here, err := os.Getwd() 100 if err != nil { 101 return nil, err 102 } 103 if err = os.MkdirAll(path.Join(dir, "qdata"), 0755); err != nil { 104 return nil, err 105 } 106 if err = os.Symlink(path.Join(here, "constellation-test-keys"), path.Join(dir, "keys")); err != nil { 107 return nil, err 108 } 109 cfgFile, err := os.Create(path.Join(dir, "constellation.cfg")) 110 if err != nil { 111 return nil, err 112 } 113 err = constellationCfgTemplate.Execute(cfgFile, map[string]string{"RootDir": dir}) 114 if err != nil { 115 return nil, err 116 } 117 constellationCmd := osExec.Command("constellation-node", cfgFile.Name()) 118 var stdout, stderr bytes.Buffer 119 constellationCmd.Stdout = &stdout 120 constellationCmd.Stderr = &stderr 121 var constellationErr error 122 go func() { 123 constellationErr = constellationCmd.Start() 124 }() 125 // Give the constellation subprocess some time to start. 126 time.Sleep(5 * time.Second) 127 fmt.Println(stdout.String() + stderr.String()) 128 if constellationErr != nil { 129 return nil, constellationErr 130 } 131 private.P = constellation.MustNew(cfgFile.Name()) 132 return constellationCmd, nil 133 } 134 135 func runTessera() (*osExec.Cmd, error) { 136 tesseraVersion := "0.6" 137 // make sure JRE is available 138 if err := osExec.Command("java").Start(); err != nil { 139 return nil, fmt.Errorf("runTessera: java not available - %s", err.Error()) 140 } 141 // download binary from github/release 142 dir, err := ioutil.TempDir("", "tessera") 143 if err != nil { 144 return nil, err 145 } 146 defer os.RemoveAll(dir) 147 resp, err := http.Get(fmt.Sprintf("https://github.com/jpmorganchase/tessera/releases/download/tessera-%s/tessera-app-%s-app.jar", tesseraVersion, tesseraVersion)) 148 if err != nil { 149 return nil, err 150 } 151 defer resp.Body.Close() 152 data, err := ioutil.ReadAll(resp.Body) 153 if err != nil { 154 return nil, err 155 } 156 tesseraJar := filepath.Join(dir, "tessera.jar") 157 if err := ioutil.WriteFile(tesseraJar, data, os.FileMode(0644)); err != nil { 158 return nil, err 159 } 160 // create config.json file 161 here, err := os.Getwd() 162 if err != nil { 163 return nil, err 164 } 165 if err = os.MkdirAll(path.Join(dir, "qdata"), 0755); err != nil { 166 return nil, err 167 } 168 tmIPCFile := filepath.Join(dir, "qdata", "tm.ipc") 169 keyData, err := ioutil.ReadFile(filepath.Join(here, "constellation-test-keys", "tm1.key")) 170 if err != nil { 171 return nil, err 172 } 173 publicKeyData, err := ioutil.ReadFile(filepath.Join(here, "constellation-test-keys", "tm1.pub")) 174 if err != nil { 175 return nil, err 176 } 177 tesseraConfigFile := filepath.Join(dir, "config.json") 178 if err := ioutil.WriteFile(tesseraConfigFile, []byte(fmt.Sprintf(` 179 { 180 "useWhiteList": false, 181 "jdbc": { 182 "username": "sa", 183 "password": "", 184 "url": "jdbc:h2:./qdata/c0/db0;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0" 185 }, 186 "server": { 187 "port": 9000, 188 "hostName": "http://localhost", 189 "sslConfig": { 190 "tls": "OFF", 191 "generateKeyStoreIfNotExisted": true, 192 "serverKeyStore": "./qdata/c1/server1-keystore", 193 "serverKeyStorePassword": "quorum", 194 "serverTrustStore": "./qdata/c1/server-truststore", 195 "serverTrustStorePassword": "quorum", 196 "serverTrustMode": "TOFU", 197 "knownClientsFile": "./qdata/c1/knownClients", 198 "clientKeyStore": "./c1/client1-keystore", 199 "clientKeyStorePassword": "quorum", 200 "clientTrustStore": "./c1/client-truststore", 201 "clientTrustStorePassword": "quorum", 202 "clientTrustMode": "TOFU", 203 "knownServersFile": "./qdata/c1/knownServers" 204 } 205 }, 206 "peer": [ 207 { 208 "url": "http://localhost:9000" 209 } 210 ], 211 "keys": { 212 "passwords": [], 213 "keyData": [ 214 { 215 "config": %s, 216 "publicKey": "%s" 217 } 218 ] 219 }, 220 "alwaysSendTo": [], 221 "unixSocketFile": "%s" 222 } 223 `, string(keyData), string(publicKeyData), tmIPCFile)), os.FileMode(0644)); err != nil { 224 return nil, err 225 } 226 227 cmdStatusChan := make(chan error) 228 cmd := osExec.Command("java", "-Xms128M", "-Xmx128M", "-jar", tesseraJar, "-configFile", tesseraConfigFile) 229 // run tessera 230 go func() { 231 err := cmd.Start() 232 cmdStatusChan <- err 233 }() 234 // wait for tessera to come up 235 go func() { 236 waitingErr := errors.New("waiting") 237 checkFunc := func() error { 238 conn, err := net.Dial("unix", tmIPCFile) 239 if err != nil { 240 return waitingErr 241 } 242 if _, err := conn.Write([]byte("GET /upcheck HTTP/1.0\r\n\r\n")); err != nil { 243 return waitingErr 244 } 245 result, err := ioutil.ReadAll(conn) 246 if err != nil || string(result) != "I'm up!" { 247 return waitingErr 248 } 249 return nil 250 } 251 for { 252 time.Sleep(3 * time.Second) 253 if err := checkFunc(); err != nil && err != waitingErr { 254 cmdStatusChan <- err 255 } 256 } 257 }() 258 if err := <-cmdStatusChan; err != nil { 259 return nil, err 260 } 261 // wait until tessera is up 262 return cmd, nil 263 } 264 265 // 600a600055600060006001a1 266 // [1] PUSH1 0x0a (store value) 267 // [3] PUSH1 0x00 (store addr) 268 // [4] SSTORE 269 // [6] PUSH1 0x00 270 // [8] PUSH1 0x00 271 // [10] PUSH1 0x01 272 // [11] LOG1 273 // 274 // Store then log 275 func TestPrivateTransaction(t *testing.T) { 276 var ( 277 key, _ = crypto.GenerateKey() 278 helper = MakeCallHelper() 279 privateState = helper.PrivateState 280 publicState = helper.PublicState 281 ) 282 283 constellationCmd, err := runConstellation() 284 if err != nil { 285 if strings.Contains(err.Error(), "executable file not found") { 286 if constellationCmd, err = runTessera(); err != nil { 287 t.Fatal(err) 288 } 289 } else { 290 t.Fatal(err) 291 } 292 } 293 defer constellationCmd.Process.Kill() 294 295 prvContractAddr := common.Address{1} 296 pubContractAddr := common.Address{2} 297 privateState.SetCode(prvContractAddr, common.Hex2Bytes("600a600055600060006001a1")) 298 privateState.SetState(prvContractAddr, common.Hash{}, common.Hash{9}) 299 publicState.SetCode(pubContractAddr, common.Hex2Bytes("6014600055")) 300 publicState.SetState(pubContractAddr, common.Hash{}, common.Hash{19}) 301 302 if publicState.Exist(prvContractAddr) { 303 t.Error("didn't expect private contract address to exist on public state") 304 } 305 306 // Private transaction 1 307 err = helper.MakeCall(true, key, prvContractAddr, nil) 308 if err != nil { 309 t.Fatal(err) 310 } 311 stateEntry := privateState.GetState(prvContractAddr, common.Hash{}).Big() 312 if stateEntry.Cmp(big.NewInt(10)) != 0 { 313 t.Error("expected state to have 10, got", stateEntry) 314 } 315 if len(privateState.Logs()) != 1 { 316 t.Error("expected private state to have 1 log, got", len(privateState.Logs())) 317 } 318 if len(publicState.Logs()) != 0 { 319 t.Error("expected public state to have 0 logs, got", len(publicState.Logs())) 320 } 321 if publicState.Exist(prvContractAddr) { 322 t.Error("didn't expect private contract address to exist on public state") 323 } 324 if !privateState.Exist(prvContractAddr) { 325 t.Error("expected private contract address to exist on private state") 326 } 327 328 // Public transaction 1 329 err = helper.MakeCall(false, key, pubContractAddr, nil) 330 if err != nil { 331 t.Fatal(err) 332 } 333 stateEntry = publicState.GetState(pubContractAddr, common.Hash{}).Big() 334 if stateEntry.Cmp(big.NewInt(20)) != 0 { 335 t.Error("expected state to have 20, got", stateEntry) 336 } 337 338 // Private transaction 2 339 err = helper.MakeCall(true, key, prvContractAddr, nil) 340 stateEntry = privateState.GetState(prvContractAddr, common.Hash{}).Big() 341 if stateEntry.Cmp(big.NewInt(10)) != 0 { 342 t.Error("expected state to have 10, got", stateEntry) 343 } 344 345 if publicState.Exist(prvContractAddr) { 346 t.Error("didn't expect private contract address to exist on public state") 347 } 348 if privateState.Exist(pubContractAddr) { 349 t.Error("didn't expect public contract address to exist on private state") 350 } 351 }