Ich schlage mir seit einigen Stunden den Kopf darüber, ich würde mich über jede Hilfe freuen :)
Dies ist eine abschließende Bearbeitung, um das Problem klar zu formulieren: Gibt es eine geeignete Möglichkeit, ein bytes32-Array an eine Methode für Vertrag B zu übergeben, die selbst einen Vertrag A (von seiner Adresse) instanziiert und das bytes32-Array an eine Methode dieses Vertrags übergibt ? Das Array direkt an die Methode von Vertrag A zu übergeben, funktioniert problemlos, aber es an die Methode von Vertrag B zu übergeben, die es wiederum an die Methode von Vertrag A übergibt, funktioniert nicht, wenn das Array mehr als ein Byte hat32.
Ist das eine Einschränkung der Solidität? Oder mache ich etwas falsch (in Solidität oder mit meinem Javascript-Web3js-Code)? Oder ist das ein Fehler bei testrpc?
Alle Details unten. Lassen Sie mich wissen, ob Sie das Problem reproduzieren können, oder ob das gut funktioniert oder so.
Ich habe einen Vertrag A und einen Vertrag B, der davon erbt. Ich möchte einen Vertrag A in Vertrag B von einer bereits bereitgestellten Adresse des Vertrags A instanziieren und die Methoden dieser Instanz aufrufen.
Ich weiß, wie das geht (oder zumindest denke ich, dass ich es tue; vielleicht ist es nicht der richtige Weg, es zu tun?) Und es funktioniert. Das eigentliche Problem ist das Array von bytes32.
Hier ist vor allem der Vertragscode.
contract A {
struct MyStruct {
address user;
bytes32 [] stuff;
}
MyStruct [] public myStructs;
function addStuff (bytes32 [] _stuff) public {
myStructs.push (
MyStruct ({user: msg.sender, stuff: _stuff})
);
}
}
contract B is A {
function provideStuff (address to, bytes32 [] stuff) public {
A(to).addStuff(stuff);
}
}
Ein bisschen Kontext: stuff
ist ein hexadezimaler String (der 256 Bit = 32 Bytes sein kann (passt perfekt in ein bytes32
) oder mehr (512 usw.); daher das Array bytes32[]
).
Zuerst stelle ich einen Vertrag A (Rückgabe einer Instanz contractA
) mit der Wallet-Adresse bereit anAddress
. Dies gibt mir, wenn mein Vertrag bereitgestellt wird, die Smart-Contract-Adresse contractAaddress
.
Der Aufruf addStuff
mit einem Array von bytes32 funktioniert einwandfrei:
gasEstimate = contractA.addStuff.estimateGas(getBytes32Array(stuff), {from: anAddress);
contractA.addStuff(getBytes32Array(stuff), {from: anAddress, gas: gasEstimate});
Ich habe eine Funktion, getBytes32Array
die ein Array von Bytes32 (tatsächlich hexadezimale Zeichenfolgen) aus einer bestimmten hexadezimalen Zeichenfolge ausgibt:
function getBytes32Array(string){
var splittedString = string.match(/.{1,64}/g);
for(var i=0; i< splittedString.length; i++){
splittedString[i] = "0x"+splittedString[i];
}
return splittedString;
}
Dadurch kann ich beispielsweise einfach meinen Hex-String e0f89ca8eae95281590977802df657506a151304234d15570c12cc26263a8b7a2bf140bc9f80baa93879634717d9c2cf08cc6c96492c1b56c053ae54546f4f20
(512 Bit) eingeben und erhalten, ["0xe0f89ca8eae95281590977802df657506a151304234d15570c12cc26263a8b7a","0x2bf140bc9f80baa93879634717d9c2cf08cc6c96492c1b56c053ae54546f4f20"]
was als Bytes32-Array verstanden wird, das zwei Bytes32 enthält.
Der Aufruf addStuff
auf diese Weise funktioniert perfekt mit einem Array von Bytes32, das mehr als ein Byte32 enthält.
Zweitens stelle ich jetzt meinen Vertrag B (Rückgabe einer Instanz contractB
) mit der Wallet-Adresse bereit anotherAddress
. Dies gibt mir, wenn mein Vertrag bereitgestellt wird, die Smart-Contract-Adresse contractBaddress
.
Was ich tun möchte, ist, die provideStuff
Methode von Vertrag B aufzurufen und ihr die Adresse des bereitgestellten Vertrags A contractAaddress
und die stuff
, die den Vertrag A aus der Adresse instanziieren und die addStuff
mit der stuff
bereitgestellten aufrufen soll, zuzuführen. (siehe Vertrag B Soliditätscode)
gasEstimate = contractB.provideStuff.estimateGas(contractAaddress, getBytes32Array(stuff), {from: anotherAddress});
contractB.provideStuff(contractAaddress, getBytes32Array(stuff), {from: anotherAddress, gas: gasEstimate});
Aber das gibt mir jedes Mal einen ungültigen Op-Code ... Trotz der Arbeit von "schätzenGas" (ist das nicht komisch?) ... Das funktioniert , wenn mein bytes32-Array nur ein bytes32 hat. Noch seltsamer, es funktioniert auch, wenn es ein zweites bytes32 hat, das eine sehr kurze Hex-Zeichenfolge ist ( siehe PS1 ). Aber ich kann kein konsistentes Verhalten mit einem Array von x Bytes32 bekommen, jeweils 32 Bytes (64 Zeichen) Hex-Strings (oder noch kürzer) ...
Vielen Dank im Voraus.
PS1: Das vorherige Beispiel funktioniert gut, wenn das Zeug ein 256-Bit-Hex-Wert oder etwas länger ist (ich habe es mit Hardcoding versucht ["0x256BitValueHere","0xverySmallValueHere"]
, 0xverySmallValueHere
kann nicht länger als ein paar Zeichen sein (vielleicht 10, ich erinnere mich nicht), danach wird ungültige Op ausgelöst Codieren Sie erneut. Ich habe es auch mit mehreren kleinen Werten versucht ["0xverySmallValueHere", "0xverySmallValueHere", "0xverySmallValueHere", "0xverySmallValueHere"]
, es wird auch nicht funktionieren.
PS2: lokal mit testrpc arbeiten.
EDIT : Alles funktioniert perfekt in Remix. Es ist also kein Solidity-Code-Problem.
Sie verwechseln das "Instanziieren" von Vertrag A mit dem "Erben von" Vertrag A.
Vererbung ist eher wie Klassenbibliotheken, in denen B die Zustandsvariablen und Funktionen von A übernimmt. Es gibt kein separates A, mit dem man in dem Fall sprechen kann - nur contract B is A
B, das zufällig Quellcode von A enthält.
Da Sie möchten, dass zwei Verträge miteinander kommunizieren, stellen Sie zuerst A bereit und sprechen Sie dann in B darüber. Die einfachste Methode besteht darin, dass die Quelldatei von B eine Kopie von A enthält, damit der Compiler sie „sehen“ und die ABI (Funktion) verstehen kann Zeichen). Es gibt keine B is A
, aber Sie können eine Variable contract A
wie folgt in den Typ "be" umwandeln:
A a;
(so ähnlich uint x
).
Nachdem nun der „Typ“ von „a“ festgelegt ist, ist der andere wichtige Faktor seine Adresse. Angenommen, Sie haben A bereits irgendwo bereitgestellt, sollten Sie seine Adresse kennen. Sie können das an den Konstruktor von B übergeben und die Instanziierung von "a" abschließen.
function B(address aAddress) public {
a = A(aAddress); // so "a" is the "A" found at "aAddress"
}
Großartig. Jetzt können Sie mit Nachrichten hin und her senden a.function(args)
.
Hier ist eine kleine Bastelei ähnlich wie bei dir:
pragma solidity 0.4.17;
contract A {
event LogTest(address sender, bytes32 element);
function test(bytes32[] X) public returns(bool success) {
// This unbounded loop is an anti-pattern, but it shows it working at small scales.
for(uint i=0; i<X.length; i++) {
LogTest(msg.sender, X[i]);
}
return true;
}
}
contract B {
A a; // variable "a" cast as type "A" which is the contract shown above
function B(address aAddress) public {
a = A(aAddress); // instantiate an instance of "a" already deployed at the address passed in
}
function testIt(bytes32[] array) public returns(bool success) {
return a.test(array); // send a message to contract "a"
}
}
Sie können in Remix herumspielen, um zu sehen, wie es funktioniert.
["0x1","0x2"]
um ihm ein Array zu übergeben.Ich hoffe es hilft.
Ich habe gerade Ihren Vertrag in Remix (Solidity Version 0.4.24) ausprobiert und es funktioniert gut. Ich kann Sachen per Vertragsmethode schreiben provideStuff
und B
sie dann per Vertrag lesen A
. Allerdings musste ich die folgende Methode in den Vertrag aufnehmen, A
um Sachen daraus zu lesen:
function get (uint i, uint j) public view returns (bytes32) {
return myStructs [i].stuff [j];
}
da der von Solidity generierte Standard-Getter keine dynamischen Arrays liest.
Hillfias
Hillfias